最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

环球热议:EF7数据库提供者的自定义值生成器

来源:博客园


(相关资料图)

本文将讲解提供者使用值生成器的原理。因代码太多,本文只摘要重要代码,并且删除了代码中的注释。如果您不了解,如何使用EF的值生成器?

SqlServer提供者:

Microsoft.EntityFrameworkCore.SqlServer如下代码:我们可以看到提供者已经帮我们实现好了顺序Guid自定义值生成器。

public class SequentialGuidValueGenerator : ValueGenerator{    private long _counter = DateTime.UtcNow.Ticks;    public override Guid Next(EntityEntry entry)    {        var guidBytes = Guid.NewGuid().ToByteArray();        var counterBytes = BitConverter.GetBytes(Interlocked.Increment(ref _counter));        if (!BitConverter.IsLittleEndian)        {            Array.Reverse(counterBytes);        }        guidBytes[08] = counterBytes[1];        guidBytes[09] = counterBytes[0];        guidBytes[10] = counterBytes[7];        guidBytes[11] = counterBytes[6];        guidBytes[12] = counterBytes[5];        guidBytes[13] = counterBytes[4];        guidBytes[14] = counterBytes[3];        guidBytes[15] = counterBytes[2];        return new Guid(guidBytes);    }    public override bool GeneratesTemporaryValues => false;}

有了值生成器,我们来看看数据库提供者是如何使用的。首先它帮我们写了生成值选择器,而只有在属性为Guid类型,切是需要生成值的状态下使用自动使用 SequentialGuidValueGenerator 值生成器。如下代码所示:

public class SqlServerValueGeneratorSelector : RelationalValueGeneratorSelector{    protected override ValueGenerator? FindForType(IProperty property, IEntityType entityType, Type clrType)        => property.ClrType.UnwrapNullableType() == typeof(Guid)            ? property.ValueGenerated == ValueGenerated.Never || property.GetDefaultValueSql() != null                ? new TemporaryGuidValueGenerator()                : new SequentialGuidValueGenerator()            : base.FindForType(property, entityType, clrType);}

SqlServerValueGeneratorSelector 将附加到 AddEntityFrameworkSqlServer 中第109行。AddEntityFrameworkSqlServer 将被附加到 ApplyServices 中第66行。最终 ApplyServices 将为EF 核心内部API 解释服务与功能。

MySql提供者:

Pomelo.EntityFrameworkCore.MySql首先,MySql提供者与SqlServer提供者的原理是一样的机制。不过为了适配Mysql的uuid(RFC 4122)规范,提供者写了属于Mysql的顺序Guid自定义值生成器。

public class MySqlSequentialGuidValueGenerator  : ValueGenerator{    private readonly IMySqlOptions _options;    public MySqlSequentialGuidValueGenerator(IMySqlOptions options)    {        _options = options;    }    private static readonly RandomNumberGenerator _rng = RandomNumberGenerator.Create();    public override Guid Next(EntityEntry entry)    {        return Next();    }    public Guid Next()    {        return Next(DateTimeOffset.UtcNow);    }    public Guid Next(DateTimeOffset timeNow)    {        var randomBytes = new byte[7];        _rng.GetBytes(randomBytes);        var ticks = (ulong) timeNow.Ticks;        var uuidVersion = (ushort) 4;        var uuidVariant = (ushort) 0b1000;        var ticksAndVersion = (ushort)((ticks << 48 >> 52) | (ushort)(uuidVersion << 12));        var ticksAndVariant = (byte)  ((ticks << 60 >> 60) | (byte)  (uuidVariant << 4));        if (_options.ConnectionSettings.GuidFormat == MySqlGuidFormat.LittleEndianBinary16)        {            var guidBytes = new byte[16];            var tickBytes = BitConverter.GetBytes(ticks);            if (BitConverter.IsLittleEndian)            {                Array.Reverse(tickBytes);            }            Buffer.BlockCopy(tickBytes, 0, guidBytes, 0, 6);            guidBytes[6] = (byte)(ticksAndVersion << 8 >> 8);            guidBytes[7] = (byte)(ticksAndVersion >> 8);            guidBytes[8] = ticksAndVariant;            Buffer.BlockCopy(randomBytes, 0, guidBytes, 9, 7);            return new Guid(guidBytes);        }        var guid = new Guid((uint) (ticks >> 32), (ushort) (ticks << 32 >> 48), ticksAndVersion,            ticksAndVariant,            randomBytes[0],            randomBytes[1],            randomBytes[2],            randomBytes[3],            randomBytes[4],            randomBytes[5],            randomBytes[6]);        return guid;    }    public override bool GeneratesTemporaryValues => false;}

与SqlServer提供者同理,值生成器附加到MysqlValueGeneratorSelector,MysqlValueGeneratorSelector又附加到 AddEntityFramwrokMySql中,AddEntityFramwrokMySql又被附加到AppServices中。

总结

我们了解到了EF的数据库提供者使用值生成器的原理,知道了每个数据库的Guid算法不一样。还了解到数据库提供者的帮助,我们使用EF时不用过多的关心,数据库数据类型值的生成方式。

关键词: 数据库提供者 自定义值 生成方式