EF Core预编译模型Compiled Model

这篇具有很好参考价值的文章主要介绍了EF Core预编译模型Compiled Model。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

最近还在和 npgsqlEF Core 斗争,由于 EF Core 暂时还不支持 AOT,因此在 AOT 应用程序中使用 EF Core 时,会提示问题:

EF Core预编译模型Compiled Model

听这个意思,似乎使用 Compiled Model 可以解决问题,于是就又研究了一下 EF Core 的这个功能。

在 EF Core 中,模型根据实体类和配置构建,默认情况下,每次创建一个新的 DbContext 实例时,EF Core 都会构建模型。对于需要频繁创建 DbContext 实例的应用程序,这可能会导致性能问题。

Entity Framework Core(EF Core)的预编译模型(Compiled Model)对应提供了一种优化,在 EF Core 6 preview 5 中首次增加了这个功能,可以让设计人员预编译模型,避免在后续执行查询时动态生成模型。

预编译模型的优势

  1. 性能提升:通过预编译模型,可以减少应用程序启动时的开销,特别是对于大型模型。

此处的启动时间,指 DbContext 的首次启动时间,由于延迟查询的机制,一般 DbContext 并不会在新建对象时完成启动,而是在首次执行插入或者查询时完成这个过程。

参考下图(来自参考 1):
EF Core预编译模型Compiled Model

显然,随着模型的规模增大,启动时间线性增长;但是使用预编译模型后,启动时间和模型大小基本无关,保持在一个极低的水平。

  1. 一致性:确保每个 DbContext 实例使用相同的模型配置。

使用预编译模型

  1. 生成编译模型
    使用 EF Core 命令行工具,命令:
dotnet ef dbcontext optimize

这将生成 DbContext 的预编译模型。我只有一个 POCO 类,生成了 3 个文件,类名称就是文件名称。

[DbContext(typeof(DataContext))]
public partial class DataContextModel : RuntimeModel
{
    static DataContextModel()
    {
        var model = new DataContextModel();
        model.Initialize();
        model.Customize();
        _instance = model;
    }

    private static DataContextModel _instance;
    public static IModel Instance => _instance;

    partial void Initialize();

    partial void Customize();
}
public partial class DataContextModel
{
    partial void Initialize()
    {
        var deviceDatum = DeviceDatumEntityType.Create(this);

        DeviceDatumEntityType.CreateAnnotations(deviceDatum);

        AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
        AddAnnotation("ProductVersion", "8.0.0-rc.2.23480.1");
        AddAnnotation("Relational:MaxIdentifierLength", 63);
        AddRuntimeAnnotation("Relational:RelationalModel", CreateRelationalModel());
    }

    private IRelationalModel CreateRelationalModel()
    {
	    // 这里面非常多描述类型的代码,节约篇幅我就不写全了。
        var relationalModel = new RelationalModel(this);

        var deviceDatum = FindEntityType("AspireSample.DeviceDatum")!;

        var defaultTableMappings = new List<TableMappingBase<ColumnMappingBase>>();
        deviceDatum.SetRuntimeAnnotation("Relational:DefaultMappings", defaultTableMappings);
        
	    ....
	    
        return relationalModel.MakeReadOnly();
    }
}
internal partial class DeviceDatumEntityType
{
    public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType baseEntityType = null)
    {
        var runtimeEntityType = model.AddEntityType(
            "AspireSample.DeviceDatum",
            typeof(DeviceDatum),
            baseEntityType);

        var id = runtimeEntityType.AddProperty(
            "Id",
            typeof(string),
            propertyInfo: typeof(DeviceDatum).GetProperty("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
            fieldInfo: typeof(DeviceDatum).GetField("<Id>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
            afterSaveBehavior: PropertySaveBehavior.Throw);
        id.TypeMapping = StringTypeMapping.Default.Clone(
            comparer: new ValueComparer<string>(
                (string v1, string v2) => v1 == v2,
                (string v) => v.GetHashCode(),
                (string v) => v),
            keyComparer: new ValueComparer<string>(
                (string v1, string v2) => v1 == v2,
                (string v) => v.GetHashCode(),
                (string v) => v),
            providerValueComparer: new ValueComparer<string>(
                (string v1, string v2) => v1 == v2,
                (string v) => v.GetHashCode(),
                (string v) => v),
            mappingInfo: new RelationalTypeMappingInfo(
                dbType: System.Data.DbType.String));
                
        ......

        var key = runtimeEntityType.AddKey(
            new[] { id });
        runtimeEntityType.SetPrimaryKey(key);

        return runtimeEntityType;
    }

    public static void CreateAnnotations(RuntimeEntityType runtimeEntityType)
    {
        runtimeEntityType.AddAnnotation("Relational:FunctionName", null);
        runtimeEntityType.AddAnnotation("Relational:Schema", null);
        runtimeEntityType.AddAnnotation("Relational:SqlQuery", null);
        runtimeEntityType.AddAnnotation("Relational:TableName", "devicedata");
        runtimeEntityType.AddAnnotation("Relational:ViewName", null);
        runtimeEntityType.AddAnnotation("Relational:ViewSchema", null);

        Customize(runtimeEntityType);
    }

    static partial void Customize(RuntimeEntityType runtimeEntityType);
}

可以看到,优化工具帮我们生成了非常多的代码,尤其是与类型描述相关的代码,因此,如果我们修改模型,那么必须重新执行一遍对应的生成指令。

  1. 修改 DbContext
    修改你的 DbContext 类,让它使用这个预编译模型。
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    if (!optionsBuilder.IsConfigured)
    {
        // 指定编译模型的使用
        optionsBuilder.UseModel(CompiledModels.MyCompiledModel.Instance);
    }
}

权衡利弊

核心优点:

  1. 提升启动速度,对实体类型较多的 DbContext 尤其显著。

缺点:

  1. 不支持全局查询过滤、Lazy loading proxiesChange tracking proxies 和自定义 IModelCacheKeyFactory
  2. 每次修改模型都必须重新生成优化代码。

不支持的东西很多,每次修改模型还需要重新生成就非常麻烦,因此,如果不是真的启动速度已经非常慢了不建议使用

后记

我在使用 EF Core 的 Compiled Model 之后依然提示相同的错误,后来发现错误是从 Reflection 相关类爆出的,而不是 EF Core 的相关类。所以错误里说的 Compiled Model 和 EF Core 的 Compiled Model 概念不同,应该指 AOT 不支持反射中动态加载,需要提前编译。现在 EF Core 还没完全准备好,因此,重申一下,EF Core 8 暂时不支持 AOT文章来源地址https://www.toymoban.com/news/detail-746865.html

参考

  • Announcing Entity Framework Core 6.0 Preview 5: Compiled Models - .NET Blog (microsoft.com)
  • Advanced Performance Topics | Microsoft Learn

到了这里,关于EF Core预编译模型Compiled Model的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【EF Core】实体的主、从关系

    假设有以下两个实体: Homework 类表示家庭作业,它并不是独立使用的,而是与学生类(Student)有依赖关系。一位学生有多个家庭作业记录,即 Homework 对象用于记录每位同学的作业的。按照这样的前提,Student 是主对象,Homework 是从对象。 Student 对象有个 Homeworks 属性,用于引

    2024年02月11日
    浏览(44)
  • Net Core中使用EF Core连接Mysql数据库

    Entity Framework Core的前身是微软提供并主推的ORM框架,简称EF,其底层是对ADO.NET的封装。EF支持SQLServer、MYSQL、Oracle、Sqlite等所有主流数据库。 首先是使用时的几个模式的整理及其理解: Code First:根据代码自动创建数据库表结构甚至是数据库,可以支持多库开发,代码较少冗余

    2024年01月24日
    浏览(50)
  • EF Core + MySQL 基本增删改查

    基于EF Core + MySQL的基本增删改查,示例是基于.NET6 + EF Core + MySQL 创建实体和数据库、EFCore 数据迁移项目基础上的内容增加。同时也是对基于Canal实现MySQL 8.0 数据库数据同步项目的验证。 Controllers----添加----控制器,选择api----包含读写操作的API控制器。 将上下文类注入到User

    2024年02月08日
    浏览(47)
  • EF Core 在实际开发中,如何分层?

    分层就是将 EF Core 放在单独的项目中,其它项目如 Asp.net core webapi 项目引用它 这样的好处是解耦和项目职责的清晰划分,并且可以重用 EF Core 项目 但是也会数据库迁移变得复杂起来 创建一个 .NET 类库项目,项目名字为 BooksEFCore 引用以下 Nuget 包 Microsoft.EntityFrameworkCore.Relati

    2024年01月24日
    浏览(44)
  • 使用EF Core创建webapi接口(二)

    有错误欢迎大家给我指正 说明:netcore webapi+net6+EF Core版本,codefirst模式(代码创建数据库) 1.netcore webapi+net6+EF Core版本,dbfirst模式(代码生成数据库)见:使用EF Core创建webapi接口(一)-CSDN博客 2.netcore webapi+net6+EF Core+vue前后端联动版本,见netcore webapi+net6+EF Core+vue3前后端联动-CSD

    2024年02月21日
    浏览(44)
  • Ef Core花里胡哨系列(4) 多租户

    当然,我们要考虑设计问题,例如,切换 Schema 或者改变数据库时, Ef Core 同样也会刷新改实体的缓存,所以,首次查询将会很慢,不适合大表。 在我的上一篇博客中 [Ef Core花里胡哨系列(3) 动态修改实体对应的表(分表)、多租户] 中我们实现了如何分表,同理,我们可以用近

    2024年02月03日
    浏览(35)
  • EF Core实操,数据库生成实体,迁移

    大家好,我是行不更名,坐不改姓的宋晓刚,下面将带领大家进入C#编程EF Core数据库基础入门知识,如何连接数据库,如何编写代码,跟上我的步伐进入EF Core数据库下的世界。 家人们,如果有什么不懂,可以留言,或者加我联系方式,一起进入微软技术的开拓。 微信:153

    2024年01月22日
    浏览(42)
  • 如何在 EF Core 中使用乐观并发控制

    乐观并发控制是一种处理并发访问的数据的方法,它基于一种乐观的假设,即认为并发访问的数据冲突的概率很低。在乐观并发控制中,系统不会立即对并发访问的数据进行加锁,而是在数据被修改时,再检查是否有其他并发操作已经修改了数据。如果检测到冲突,系统 再采

    2024年02月04日
    浏览(41)
  • ASP.NET Core Web API入门之三:使用EF Core

    一般来讲我们做项目都会用实体类跟数据库实体进行关系对应,这样的好处方便我们维护、增删改查,并且可以减少SQL的编写,从而统一风格,那么 Entity Framework Core 就是很不错的ORM框架。 1、跨数据库支持能力强大,只需修改配置就可以轻松实现数据库切换。 2、提升了开发效

    2024年02月10日
    浏览(53)
  • .NET6.0 EF Core连接sql

    1、先导入四个包 Microsoft.EntityFrameworkCore Microsoft.EntityFrameworkCore.Relational Microsoft.EntityFrameworkCore.SqlServer Microsoft.EntityFrameworkCore.Tools 2、在程序包管理控制台执行 Scaffold-DbContext \\\"server=.;Integrated Security=true;database=DBStu\\\" Microsoft.EntityFrameworkCore.SqlServer -OutPutDir Models Models是你实体类安放

    2024年02月06日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包