首页 > 数据库 >EF7数据库提供者的自定义值生成器

EF7数据库提供者的自定义值生成器

时间:2023-03-07 13:26:18浏览次数:67  
标签:自定义 提供者 public 生成器 EF7 counterBytes Guid guidBytes

本文将讲解提供者使用值生成器的原理。因代码太多,本文只摘要重要代码,并且删除了代码中的注释。
如果您不了解,如何使用EF的值生成器?见这篇文章:《EF7创建模型值生成篇》

SqlServer提供者:

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

public class SequentialGuidValueGenerator : ValueGenerator<Guid>
{
    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<Guid>
{

    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时不用过多的关心,数据库数据类型值的生成方式。

标签:自定义,提供者,public,生成器,EF7,counterBytes,Guid,guidBytes
From: https://www.cnblogs.com/YataoFeng/p/17187772.html

相关文章

  • EF7创建模型值生成篇
    在EF7中,生成的值是非常重要的,因为它们决定了数据库表中的数据。在本文中,我们将以人员为例,使用FluentAPI展示所有EF7生成值的功能。我们先来看一下人员表的属性:pub......
  • HANA-BW-改造自定义数据源
    1HANA-BW-改造自定义数据源22020年5月13日312:534ZMM_TRAN_KONV改为hana触发器增量上载5源代码:6OPENCURSORWITHHOLDS_CURSORFOR7......
  • 5 odoo 自定义界面
    本文以项目模块自定义工作台为例模块名称:my_projectodoo的自定义界面实现主要的两个工具:Qweb、js正式开始之前在需要自定义内容的模块中定义几个文件:static/js/proje......
  • python - 生成器与迭代器
    2、生成器的用法#生成器的作用是节省空间,生成器就是迭代器的一种#defindex():#print('index')#yield123#yield后面如果没有加参数会打印none#......
  • 关于有些下拉框自定义样式未生效问题
    像一些下拉框自定义类名时,在DOM树中是在body下面的,所以加/deep/和important不起作用    也就是说自定义类名有,但是类名上写的样式不起作用解决办法,在全局样式书......
  • JavaScript中给带有默认参数的方法传递自定义参数
    1,有一个默认参数($event为默认参数,index为自定义参数)     @select="handleSelect(index,$event)"2,有多个默认参数(queryString,cb为默认参数,index为自定义参数......
  • lterator迭代器-Generator生成器
    什么是迭代器 迭代器iterator,使用户在容器对象(container,例如链表或数组)上遍访的对象,使用该接口无需关心对象的内部实现细节。他就跟数据库中的光标,迭代器最早出现在1......
  • EF7创建模型入门篇
    在EF7中,创建一个模型是非常重要的步骤。本文将使用微软官方文档中的指南,来学习EF7中的创建模型篇,外加一点点个人理解。实体类型在EF7中,你需要使用modelBuilder.Entity......
  • 自定义异常
    自定义异常(日常用不到)自定义异常方法:继承异常类等价于我们创造一个类,可以在里面处理产生异常后拥有的逻辑自定义异常:publicclassExceptionGeekLeeextendsExcepti......
  • 自定义Inspector面板
     usingUnityEditor;usingUnityEngine;publicenumMyType{Dev,Master}publicclassTestCode:MonoBehaviour{publicstringtestStr;p......