EntityFramework Core2.0 多对多关系配置

​ 在EF6.0 中,多对多关系配置时,系统会自动生成第三张表,来将两张有互相约束关系的表联系起来,但是在EF Core2.0中,我们需要手动建立第三张表,比如说有两个模型Passage.cs和Category.cs,若想建立两者之间的多对多关系,我们就需要借助第三张表PassageCategory来实现:

public class Passage
{
    //文章编号
    [Key]
    public long PassageId { get; set; }

    //标题
    public string Title { get; set; }

    //描述
    public string Description { get; set; }

    //内容
    public string Content { get; set; }

    //发布时间
    public DateTime PublishTime { get; set; }

    //最后编辑时间
    public DateTime LastEditTime { get; set; }

    //文章分类(使用技术等)
    public virtual IList<PassageCategory> PassageCategories { get; set; }
}
public class Category
{
    [Key]
    public int CategoryId { get; set; }

    [MaxLength(50)]
    public string CategoryName { get; set; }
    
    public virtual IList<PassageCategory> PassageCategories { get; set; }
}

public class PassageCategory
{
    public int CategoryId { get; set; }

    public Category Category { get; set; }

    public long PassageId { get; set; }

    public Passage Passage { get; set; }
}

然后添加 FluentAPI 配置,在配置多对多关系时,必须指定级联删除。

​ 先说一下EFCore的几种级联模式:

  • Cascade

    ​ 依赖的实体也一并被删除。这种级联行为只对被上下文跟踪到的实体有效。数据库里也需要设置相应的级联,确保没有被上下文跟踪到的数据也具备同样的行为。如果你通过EF来创建数据库,那么EF会为你设置好数据库的级联。

  • Restrict

    ​ 删除操作不会作用在依赖实体上,依赖实体保持不变。

  • SetNull

    ​ 依赖实体的外键被设为null。这种级联行为只对被上下文跟踪到的实体有效。数据库里也需要设置相应的级联,确保没有被上下文跟踪到的数据也具备同样的行为。如果你通过EF来创建数据库,那么EF会为你设置好数据库的级联。

  • ClientSetNull

    ​ EFCore2.0引入了一种叫作ClientSetNull的默认行为。它具有SetNull的语义,兼有Restrict的行为。从我们的经验来看,对于被跟踪的实体和数据库来说,它是最被期待也是最有用的一种行为。

​ 在为被跟踪的实体设置级联关系时,DeleteBehavior.Restrict已经成为历史。

​ 添加一个新类 PassageCategoryMap.cs 该类继承自 IEntityTypeConfiguration 接口

    public class PassageCategoryMap : IEntityTypeConfiguration<PassageCategory>
    {
        /// <summary>
        /// PassageCategories FluentAPI配置
        /// 
        /// 添加复合主键、配置多对多关系
        /// </summary>
        /// <param name="builder"></param>
        public void Configure(EntityTypeBuilder<PassageCategory> builder)
        {
            //添加复合主键
            builder.HasKey(t => new { t.PassageId, t.CategoryId });

            ///<summary>
            ///
            /// 配置Passage与PassageCategories的一对多关系
            /// 
            /// EFCore中,新增默认级联模式为ClientSetNull
            /// 
            /// 依赖实体的外键会被设置为空,同时删除操作不会作用到依赖的实体上,依赖实体保持不变,同下
            /// 
            /// </summary>
            
            //配置Passage与PassageCategories的一对多关系
            builder.HasOne(t => t.Passage).WithMany(p => p.PassageCategories).HasForeignKey(t => t.PassageId).OnDelete(DeleteBehavior.SetNull);

            //配置Category与PassageCategories的一对多关系
            builder.HasOne(t => t.Category).WithMany(p => p.PassageCategories).HasForeignKey(t => t.CategoryId).OnDelete(DeleteBehavior.SetNull);
        }
    }

​ 然后在 DbContext 类中,重写 OnModelCreating 方法添加 FluentAPI 配置

protected override void OnModelCreating(ModelBuilder builder)
{
    base.OnModelCreating(builder);

    //查找所有FluentAPI配置
    var typesToRegister = Assembly.GetExecutingAssembly().GetTypes().Where(q => q.GetInterface(typeof(IEntityTypeConfiguration<>).FullName) != null);

    //应用FluentAPI
    foreach(var type in typesToRegister)
    {
        //dynamic使C#具有弱语言的特性,在编译时不对类型进行检查

        dynamic configurationInstance = Activator.CreateInstance(type);
        builder.ApplyConfiguration(configurationInstance);
    }
}

​ 然后添加数据迁移,更新数据库,就完成了多对多关系数据库的配置。

posted @ 2018-01-12 21:41  良品青年  阅读(225)  评论(0编辑  收藏  举报