前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >EF Core如何处理多对多关系

EF Core如何处理多对多关系

作者头像
喵叔
发布2021-11-24 09:40:51
2K0
发布2021-11-24 09:40:51
举报
文章被收录于专栏:喵叔's 专栏

目录

EF Core在处理多对多关系时并不像一对一和一对多关系那样好处理,下面我们利用一个简单的电子商城购物车来讲解一下吧。

一、解决多对多

需求是这样的:用户可以将多个商品放入购物车,每个商品又属于多个购物车。我们先创建ShoppingCart和Commodity实体类。

代码语言:javascript
复制
public class ShoppingCart
{
    public int Id { get; set; }
    public ICollection<Commodity> Commoditys{ get; set; }
}
public class Commodity
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Quantity { get; set; }
    public ICollection<ShoppingCart> ShoppingCarts{ get; set; }
}

你第一眼看到这段代码是不是觉得这么做非常好?但是我要告诉你的是,到目前为止EF Core无法处理这样的代码,当你尝试添加迁移时控制台会输出如下内容:

代码语言:javascript
复制
Unable to determine the relationship represented by navigation property 'ShoppingCart.Commoditys' of type 'ICollection'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.

那么我们该怎么做呢?聪明的同学一定想到了我们可以手动创建另一个中间表,它将建立ShoppingCart和Commodity多对多的关系。

代码语言:javascript
复制
public class ShoppingCartCommodity
{
    public int ShoppingCartId { get; set; }
    public ShoppingCart ShoppingCart{ get; set; }
    public int CommodityId { get; set; }
    public Commodity Commodity{ get; set; }
}

创建完中间表ShoppingCartCommodity,我们还要修改ShoppingCart和Commodity的导航属性:

代码语言:javascript
复制
public class ShoppingCart
{
    public int Id { get; set; }
    public ICollection<ShoppingCartCommodity> Commoditys { get; set; }
}
public class Commodity
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Quantity { get; set; }
    public ICollection<ShoppingCartCommodity> ShoppingCarts{ get; set; }
}

你以为这样处理完就完美了吗?NO!!!当你再次尝试添加迁移时会出现另一个错误提示:

代码语言:javascript
复制
The entity type 'ShoppingCart' requires a primary key to be defined.

ShoppingCart没有主键,由于多对多关系因此ShoppingCart应该是复合主键。复合主键由两列组成一个主键,在EF Core中创建复合键唯一办法是在OnModelCreating中创建。

代码语言:javascript
复制
protected override void OnModelCreating(ModelBuilder builder)
{
    base.OnModelCreating(builder);
    builder.Entity<ShoppingCartCommodity>().HasKey(p => new { p.ShoppingCartId, p.CommodityId});
}

到这里可以说才解决了EF Core处理多对多的问题。解决了多对多创建表的问题,下面我们就来看一下如何进行增删查。

二、增

我们要把商品添加到购物车中,我们需要创建ShoppingCartCommodity并保存它。

代码语言:javascript
复制
var shoppingCart= db.ShoppingCarts.First(i => i.Id == 1);
var commodity= db.Commoditys.First(i => i.Id == 2);
// 方法1:使用两个类的主键ID关联
var shoppingCartCommodity1= new ShoppingCartCommodity
{
    ShoppingCartId = shoppingCart.Id,
    CommodityId = commodity.Id
};
// 放法2:使用两个类实体关联
var shoppingCartCommodity2= new ShoppingCartCommodity
{
    ShoppingCart= cart,
    Commodity= item
};
db.Add(shoppingCartCommodity2);
db.SaveChanges();
三、查

从数据库中获取数据只需使用Include查询即可。

代码语言:javascript
复制
var shoppingCartIncludingCommoditys = db.Carts.Include(shoppingCart=> shoppingCart.Commoditys).ThenInclude(row => row.Commodity).First(shoppingCart=> shoppingCart.Id == 1);
// 获取指定购物车的所有商品
var shoppingCartCommodity2= shoppingCartIncludingCommoditys.Commoditys.Select(row => row.Commodity);
// 如果有购物车ID,则可以使用Linq获取所有商品:
var shoppingCartId = 1;
var shoppingCartCommoditys= db.Commoditys.Where(commodity=> commodity.shoppingCart.Any(j => j.ShoppingCartId== shoppingCartId));
四、删

如果要删除购物车中的商品时,可以这么做:

代码语言:javascript
复制
var shoppingCartId = 1;
var commodityId= 1;
var shoppingCartCommodity= db.ShoppingCartCommoditys.First(row => row.ShoppingCartId == shoppingCartId && row.CommodityId== commodityId);
db.Remove(shoppingCartCommodity);
db.SaveChanges();

如果要从购物车中删除所有项目,可以这么做:

代码语言:javascript
复制
var shoppingCart= db.ShoppingCarts.Include(c=> c.Commodity).First(i => i.Id == 2);
db.RemoveRange(shoppingCart.Commoditys);
db.SaveChanges();
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/11/23 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 目录
    • 一、解决多对多
      • 二、增
        • 三、查
          • 四、删
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档