EFCore的关联查询
官方文档
前言:本来这种通过设置外键来关联表的方式,我只记得在大学数据库课程当中实践过,后面的实习(java)、工作当中都没有使用到通过这种设计外键来关联表,因为当存在外键时,新增或删除的时候都要去检查关联表的记录是否存在,影响IO效率;那通过什么方式解决的呢?比如当存在A表和B表存在一对多的关系是,一般会在B表设置A表id字段,插入的时候,插入A表一条记录同时插入B表多条记录。
后来工作的时候使用了微软开发的C#语言及ORM框架EFCore,同时在其他项目中看到了这种设计,尤其是通过EFCore的CodeFirst设计这种外键是非常方便的,同时查询的时候也避免了很多代码。
背景:公司里的商城项目我接手的时候,都没有使用CodeFirst,没有历史迁移记录。同时我也是第一次负责这么大的项目,也有点不敢”轻举妄动“。所以就出现了一个奇怪的现象,在后面建表过程当中,有些表存在一对多或一对一的关系,数据库中表没有设置外键,但是在代码配置了映射关系,如下第一段代码,那么在实际查询的时候可以直接使用Include()以及ThenInclude()的,但是有一天发现一个问题,如下第二段代码,当我使用了.ThenInclude(p => p.QualityService)之后,OrderItems表中的记录也不见了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Post>() .HasOne(p => p.Blog) .WithMany(b => b.Posts); }
var query = _orderRepository.Query() .Include(c => c.OrderItems) .Include(c => c.Customer) .Include(c => c.OrderShipping).ThenInclude(OrderShipping => OrderShipping.WoodenBoxType) .Include(c => c.OrderShipping).ThenInclude(OrderShipping => OrderShipping.TransportationType) .Where(c => c.CustomerId == user.Id && c.Id == id);
|
解决办法是:在配置的时候显示指定了允许外键为null
一个 OrderItem 可以没有 关联的质检服务(QualityService),这是可选的
1 2 3 4 5 6
| modelBuilder.Entity<OrderItem>(u => u.HasOne(x => x.QualityService) .WithMany() .HasForeignKey(x => x.QualityId) .IsRequired(false); });
|
下面是使用EFCore表之间一对多、一对一、多对一、多对多的关系的实体配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| public class Blog { public int Id { get; set; } public string Name { get; set; }
public IList<Post> Posts { get; } = new List<Post>(); public BlogAssets Assets { get; set; } }
public class BlogAssets { public int Id { get; set; } public byte[] Banner { get; set; }
public int? BlogId { get; set; } public Blog Blog { get; set; } }
public class Post { public int Id { get; set; } public string Title { get; set; } public string Content { get; set; }
public int? BlogId { get; set; } public Blog Blog { get; set; }
public IList<Tag> Tags { get; } = new List<Tag>(); }
public class Tag { public int Id { get; set; } public string Text { get; set; }
public IList<Post> Posts { get; } = new List<Post>(); }
|