zoukankan      html  css  js  c++  java
  • EntityFramework:再谈 “如何映射聚合?”

    背景

    在之前的文章中《DDD:使用EntityFramework的话,如果只为聚合根设计仓储,其它实体如何处理?》,我介绍了如何映射聚合以保证其语义,当时的结论是:聚合内除了聚合根之外的实体必须使用多主键,否则删除操作(Order.OrderItems.Remove(1))只会将外键更新为 Null,最开始学习如何使用 EntityFramework 来映射聚合的时候,就纠结这个问题,当时汤雪华大哥就告诉了更新为 Null 就算删除了,当时感觉是接受了,不过没有内化,这篇文章也是为了内化这种思想。

    使用多主键映射三级聚合

    模型

     1     public class Level1
     2     {
     3         public virtual int Level1Id { get; set; }
     4 
     5         public virtual ICollection<Level2> Level2s { get; set; }
     6     }
     7 
     8     public class Level2
     9     {
    10         public virtual int Level2Id { get; set; }
    11         public virtual int Level1Id { get; set; }
    12 
    13         public virtual ICollection<Level3> Level3s { get; set; }
    14     }
    15 
    16     public class Level3
    17     {
    18         public virtual int Level3Id { get; set; }
    19         public virtual int Level2Id { get; set; }
    20         public virtual int Level1Id { get; set; }
    21     }

    映射

     1             modelBuilder.Entity<Level1>()
     2                 .HasKey(x => x.Level1Id)
     3                 .Property(x => x.Level1Id)
     4                 .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
     5             modelBuilder.Entity<Level1>()
     6                 .HasMany(x => x.Level2s)
     7                 .WithRequired()
     8                 .HasForeignKey(x => x.Level1Id)
     9                 .WillCascadeOnDelete();
    10 
    11             modelBuilder.Entity<Level2>()
    12                 .HasKey(x => new { x.Level2Id, x.Level1Id })
    13                 .Property(x => x.Level2Id)
    14                 .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    15             modelBuilder.Entity<Level2>()
    16                 .HasMany(x => x.Level3s)
    17                 .WithRequired()
    18                 .HasForeignKey(x => new { x.Level2Id, x.Level1Id })
    19                 .WillCascadeOnDelete();
    20 
    21             modelBuilder.Entity<Level3>()
    22                 .HasKey(x => new { x.Level3Id, x.Level2Id, x.Level1Id })
    23                 .Property(x => x.Level3Id)
    24                 .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

    测试添加

     1             for (var i = 1; i <= 2; i++)
     2             {
     3                 var l1 = new Level1
     4                 {
     5                     Level2s = new List<Level2>
     6                     { 
     7                         new Level2
     8                         {
     9                             Level3s = new List<Level3>
    10                             {
    11                                 new Level3()
    12                             }
    13                         }
    14                     }
    15                 };
    16                 context.Level1s.Add(l1);
    17                 context.SaveChanges();
    18             }

    测试删除

    1             using (var context = new StudyContext())
    2             {
    3                 context.Level1s.First().Level2s.First().Level3s.Clear();
    4 
    5                 context.SaveChanges();
    6             }

    说明

    因为采用了多主键,所以 context.Level1s.First().Level2s.First().Level3s.Clear() 会真正的生成 delete 语句,否则只会把外键更新为 null,但是多主键感觉真是不爽,两级还可以接受。

    多主键映射这种风格可以导致“物理删除”,单主键这种风格可以导致“逻辑删除”。

    如果是逻辑删除,需要注意哪些事项?

    1. 确定何时物理删除?如何物理删除?可以后台自动根据配置的元数据定时物理删除。
    2. 报表查询的时候注意查询语句。

    为啥不用级联删除?

    级联删除是解决:rep.delete(order),双主键是解决:order.OrderItems.Clear()。

    备注

    前几天我还暗自高兴找到了“物理删除”的映射方式,今天又更喜欢“逻辑删除”了,害苦了我一位兄弟,他都是用的 “双主键”。

  • 相关阅读:
    Swagger3.X和2.X—从入门到实战
    Java工具—Lombok
    使用Java伪造测试数据
    URL
    Java 16个超级实用的工具类
    Redis一篇从入门到实战
    MongoDB一篇从入门到实战
    admin后台管理
    auth模块
    day12_01闭包函数
  • 原文地址:https://www.cnblogs.com/happyframework/p/3375410.html
Copyright © 2011-2022 走看看