从实体框架6转移到实体框架核心20
 

从实体框架6转移到实体框架核心2.0

介绍

我们最近接手了一个相当大的web应用程序开发项目,并决定投入其中 .网络核心. 一些同事早已经这样做了 .网络核心 1有混合的结果. 随着 .网络核心 2和Visual Studio 2017, 这似乎是我们团队加入他们的好时机. 这篇文章可以看作是我之前博客文章的后续, 首先开始使用实体框架6代码 并将介绍我们在使用EF Core时遇到的问题,以及我们提出的一些解决方案. 我建议先阅读前面的博文,因为它将首先提供代码核心概念的详细背景,而这篇博文将不涉及.

在阅读这篇文章时,请记住我们使用了EF Core 2.本项目为0. 在撰写本文时,这是英孚核心的最新版本,但英孚核心2.1将于2018年第二季度发布,而随着该版本的发布,情况肯定会有所改变.

EF Core vs EF 6

EF 6是一个稳定成熟的ORM,而EF Core是一个相对较新的ORM. 微软重新构建了EF Core,去掉了EF 6的许多内部依赖和提供程序(比如SQLClient)。. 从长远来看,这将使EF Core更加可扩展和轻量级. 从短期来看, 我们将不得不处理一些痛苦,因为我们在EF 6中依赖的一些特性和命令还没有实现,有些可能永远不会实现. 如果您对EF团队为未来版本所做的工作感兴趣,您可以查看 EF核心路线图.

EF Core缺少什么

在这一节中,我将介绍当我们开始使用EF Core时,对我们影响最大的领域. 要了解完整的功能对比,请参阅Microsoft Docs页面 EF Core和EF6 Feature的特征比较.

数据注释

在EF 6中,你可以选择配置你的实体来使用数据注释模式属性, 流利的API, 或者两者的结合. 作为个人设计目标,我试图用数据注解来配置一切. 我的想法是,它使实体自我描述,你只需要去一个类文件查看实体是如何配置的,而不是在实体类和上下文类之间来回反弹.

1. 在英孚的核心, 尽管使用数据注释配置的选项减少了一些,但你仍然有这个选择. 这方面的一个例子是Index属性,它允许您在实体属性上指定创建SQL Server索引. 

    [StringLength(100), Required, Index("IX_User_Username", IsUnique = true)]
    public string Username { get; set; }

EF Core不支持Index属性, 因此,您必须使用流利的API配置SQL Server索引如下所示.

modelBuilder.Entity().HasIndex(u => u.用户名).独特();

 

连接表

在EF 6中,你可以有一个多对多的连接表,通过约定,不需要为它创建一个实体,通过在两个实体中包含一个导航属性.  在下面的例子中,我们有一个User, 包含应用程序的用户, 和角色表, 包含用户在应用程序中可以拥有的安全角色.

    公开课用户
    {
        public Guid RoleId { get; set; }

        [Required, StringLength(20), Index("IX_Role_Name", IsUnique = true)]
        public string Name { get; set; }

        [StringLength (512)]
        public string Description { get; set; }

        public bool Active { get; set; } = true;

        公共枚举.RoleCode RoleCode { get; set; }

        public virtual ICollection Users { get; set; }
    }

添加迁移时, 连接表是基于实体中的两个虚拟属性创建的,如下所示.

            不知道(
                “dbo.UserRole”,
                c => new
                    {
                        User_UserId = c.Guid (nullable: false),
                        Role_RoleId = c.Guid (nullable: false),
                    })
                .PrimaryKey(t => new { t.User_UserId t.Role_RoleId})
                .ForeignKey(“dbo.User", t => t.User_UserId cascadeDelete:真)
                .ForeignKey(“dbo.Role", t => t.Role_RoleId cascadeDelete:真)
                .Index(t => t.User_UserId)
                .Index(t => t.Role_RoleId);

在EF Core 2中,没有显式连接表的多对多关系是不支持的.  为了解决这个问题, 您必须为联接表创建一个实体,并使用流利的API指定要联接的内容.

    公开课UserRole
    {
        public long UserId { get; set; }

        public long RoleId { get; set; }

        public Role Role { get; set; }

        public User User { get; set; }
    }
    OnModelCreating(ModelBuilder)
    {
        //设置用户和角色之间的多对多关系
        modelBuilder.Entity()
            .HasKey(t => new { t.UserId, t.RoleId});
        modelBuilder.Entity()
            .HasOne(pt => pt.用户)
            .WithMany(p => p.AssignedRoles)
            .HasForeignKey(pt => pt.UserId);
        modelBuilder.Entity()
            .HasOne(pt => pt.角色)
            .WithMany(t => t.用户)
            .HasForeignKey(pt => pt.RoleId);

 

映射实体到SQL Server视图

我发现将一个实体映射到SQL Server视图在需要表示一个需要通过EF进行复杂或昂贵查询的扁平视图的情况下非常有用.  一个很好的解决方法是在SQL Server中创建一个视图,然后使用 表属性. 有了Table属性,EF将视图视为SQL Server表.

    [Table("vw公司List", Schema = “dbo")]
    公共类公司List: EntityBase
    {
        (例子)
        public long 公司Id { get; set; }

不幸的是,EF Core不支持将实体映射到SQL Server视图.  有一个变通方法可以用来欺骗EF将SQL Server视图映射为一个表, 但它也有一些局限性.  你可以使用 原始SQL查询 映射到您创建的与SQL Server视图中的列匹配的实体.

    public IQueryable GetPaymentBatches()
    {
        // EF Core不支持SQL Server视图,所以必须使用FromSql
        //IQueryable paymentBatches = _context.PaymentBatchSearches;
        IQueryable paymentBatches = _context.PaymentBatchSearches.FromSql(“SELECT * FROM vwPaymentBatchSearch”);
        返回paymentBatches;
    }

这种方法最大的痛点是,EF Core将尝试生成一个迁移的实体,您创建的SQL Server视图. NotMapped属性似乎是一个让EF Core不生成迁移的好方法,但EF Core似乎忽略了它.  您可以使用流利的API解决这个问题,并告诉ModelBuilder忽略该实体.

    OnModelCreating(ModelBuilder)
    {
        //创建迁移时忽略视图
        //在创建迁移后注释掉
        modelBuilder.Ignore<公司List>();

这对于不让您的实体在SQL Server中生成一个表是非常好的, 然而,当您试图在代码中使用该实体时, 你最终会得到一个异常“不能为‘公司List’创建一个DbSet,因为这个类型没有包含在上下文的模型中。.”.

我们最终做的是注释掉ModelBuilder Ignore, 然后在迁移之前取消评论. 在迁移之后,我们再次将其注释掉. 你们可以想象, 有一半的时间,我们会忘记注释掉它,导致EF Core在迁移时创建一个新表,或者我们会忘记在迁移后注释掉它,导致异常. 因此,这个解决方案不是最优的,但它是目前唯一的解决方案.

电动工具

实体框架6电动工具提供了一些伟大的功能,当工作与代码第一和 EF芯电动工具 做了同样的事情. 视图DbContext模型DDL SQL对于部署来说是一个有用的特性,因为它为你的POCO类生成一个SQL CREATE脚本.

结论

我建议您使用EF Core .网络核心应用程序. 有一些痛点,但如果你一直在使用EF 6, 您会发现它非常容易上手,并且能够克服我们遇到的一些限制.

进一步的阅读

实体框架核心
http://docs.microsoft.com/ef/core/

比较英孚的核心 & EF6.x
http://docs.微软.com/ef/efcore-and-ef6/index

EF Core 2的新功能.0
http://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-2.0

开始使用ASP.NET核心和实体框架核心使用Visual Studio
http://docs.微软.com/aspnet/core/data/ef-mvc/

使用实体框架核心实现基础设施持久层
http://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/microservice-ddd-cqrs-patterns/infrastructure-persistence-layer-implemenation-entity-framework-core

我们正在招聘开发人员!

来和我们获奖的团队一起工作吧! 我们正在汉普顿路和里士满弗吉尼亚州寻找中高级开发职位. 查看我们的招聘页面,看看目前的职位空缺,今天就把你的简历发送给我们!

约翰Hadzima
约翰Hadzima核心因素

约翰Hadzima是马拉松咨询公司的解决方案架构师和团队负责人,也是微软认证的解决方案开发人员. 他在汉普顿路(Hampton Roads)做了20多年的开发人员,从事各种语言和数据库的开发工作,偶尔也会做手机开发人员. 约翰喜欢冲浪、公路自行车、高尔夫球,他的两个儿子让他很忙.

让我们谈谈你的项目.

我们是一家提供全方位服务的IT和数字营销公司. 我们相信,成功的项目是与客户透明合作的结果. 您是否在为您的网站或应用程序寻找更好的用户体验? 需要有经验的数据库架构师或业务分析师? 让我们谈谈!

X