【问题标题】:Update a row adding a relationed row in EF (many-to-many)更新在 EF 中添加相关行的行(多对多)
【发布时间】:2015-11-13 08:19:00
【问题描述】:

我有两个实体:OrderItem 以及它们之间的多对多关系。我有一个接收 ItemId 作为参数的方法,如下所示:

public void AddItems(int OrderId, int ItemId)
        {
            Item item = db.ItemSet.SingleOrDefault(i => i.Id == ItemId);
            Order order = db.OrderSet.SingleOrDefault(o => o.Id == OrderId);

            order.Items.Add(item);
            db.SaveChanges();
        }

ItemSet 表中有很多行,所以第一个查询很重。有没有一种方法可以在不先对“ItemSet”表进行查询的情况下将商品添加到订单中?我的意思是,我可以将 ItemId 直接添加到 Order.Items 或类似的东西吗?

【问题讨论】:

  • 如果你想做到这一点,你需要在代码中对 Joining 表建模!这样,您就可以对这些实体的创建进行更精细的控制

标签: c# .net entity-framework lambda


【解决方案1】:
        Item item = new Item { ID = ItemId };
        Order order = new Order { ID = OrderId };

        db.ItemSet.Attach(item);
        db.OrderSet.Attach(order);

        order.Items.Add(item);  

        db.SaveChanges();

只要确保你的 Order 类中有这个:

    public Order()
    {
        Items = new List<Item>();
    }

所以order.Items.Add(item);中不会出现空指针异常

【讨论】:

    【解决方案2】:

    所以你可以为实体建模,所以:

    public DbSet<Item> ItemSet {get;set;}
    public DbSet<Order> OrderSet {get;set;}
    public DbSet<ItemOrder> ItemOrders {get;set;}
    
    public class Item
    {
        public int Id {get;set;}
    }
    
    public class Order
    {
        public int Id {get;set;}
    }
    
    public class ItemOrder
    {
        [Key, Column(Order = 0)]
        public int ItemId {get;set;}
    
        [Key, Column(Order = 1)]
        public int OrderId {get;set;}
    }
    

    所以为了更新:

        public void AddItems(int OrderId, int ItemId)
        {
            var itemExists = db.ItemOrders.FirstOrDefault(x => x.OrderId == OrderId && x.ItemId == ItemId);
    
            if (itemExists != null) return;            
    
            db.ItemOrders.Add(new ItemOrder { OrderId = OrderId, ItemId = ItemId });
    
            db.SaveChanges();
        }
    

    然后您可以使用 LINQ .Join() 进行查询,非常简单。

    为了完整起见,OP 提到导航属性现在已经消失。所以如果你知道OrderId 那么你可以简单地做:

    var items = db.ItemOrders.GroupJoin(
                    db.ItemSet,
                    io => io.ItemId,
                    i => i.Id,
                    (itemOrder, items) => items)
                  .ToList();
    

    因此,为了引导您完成,GroupJoin 要求您提供要加入的数据的 IQueryable/IEnumerable

    第二个参数是初始数据集的字段,即ItemOrders要加入的集合。

    第三个参数是要加入的集合的字段,即ItemSet

    第四个参数基本上是一个Select,在这里你会看到一个Func签名,大致是(ItemOrder itemInFirstSet, IEnumerable&lt;Item&gt; itemsThatAreJoined)

    您可以将相同的逻辑应用于 LINQ Join 扩展。但不是itemsThatAreJoined,而是itemThatIsJoined。所以区别是GroupJoin会找到多个匹配的实体,Join只会找到一个。

    这不是详细的解释,更多的是概述

    【讨论】:

    • 但是我失去了导航属性并且不能在Order.Items上进行foreach,例如。
    • 你可以,你只需要制定一个不同的查询!一切皆有可能
    • 对不起,我不明白。这比在ItemSet 表中查询更有效吗?如果 Item 很多,ItemOrders 表中的记录会更多。
    • 因此,在您的示例中,您要查询表来询问特定实体,然后将实体添加到另一个实体并保存。在我的示例中,您正在查询一个表并要求一个实体,如果它不存在则添加它。因为该表使用复合键,它将针对该键建立索引,因此查找速度将非常快。所以 TL;DR:它的两个表查询对一个。
    • 是的,我不确定。该表将有更多记录。请记住,每次添加项目时,都会创建一条记录。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-16
    • 2018-11-26
    • 1970-01-01
    • 2014-05-19
    • 1970-01-01
    相关资源
    最近更新 更多