EF 4.1代码优先 - 如何自动更新/删除多对多的连接表条目

时间:2013-05-20 13:47:19

标签: c# entity-framework ef-code-first many-to-many

我有2个实体,比方说,Trip和Activity。它们之间的关系是多对多的,因此EF会自动创建一个连接表。

实体旅行属性:
-Id(PK)由数据库生成 -name
-Description
-Property1
-Property2
-Property3

实体活动属性(此实体包含固定记录 - 只读 - 在执行插入时不会插入任何记录):
-Id(PK)由数据库生成 -name
-Description
-Cost

连接表包含2列,即上述实体的ID,同时是主键和外键。

插入条目时没有问题,自动EF创建连接表TripActivities并成功添加条目。此外,条目也成功添加到实体Trip中,并保留未更改的实体Activity。

我的问题是更新条目,例如, - 假设用户可以从GUI修改与旅行相关的信息 - 所以我从此GUI获取所有信息,并执行以下步骤来更新现有旅行:

   Trip trip = Context.Trips.Find(id); // Search for the appropriate trip to update from Id

   trip.Name = ObtainNameFromGUI();
   trip.Description = ObtainDescriptionFromGUI();
   trip.Property1 = ObtainProperty1FromGUI();
   trip.Property2 = ObtainProperty2FromGUI();
   trip.Property3 = ObtainProperty3FromGUI();
   trip.Activities = new List<Activity>();

   // From the GUI user selects from a checkbox list the activities associated to the trip
   // So we read its Ids and from those ids we fetch from database the activities to obtain
   // the info related to each activity selected in the GUI. This is all done inside the
   // below method.
   List<Activity> activities = this.ObtainActivitiesSelectedFromGUI();

   // If no activites selected (=null) I want EF automatically deletes the entries in the
   // joined table for this trip. And of course, if there are activities selected, EF 
   // should update the respectives entries in the joined table for this trip with the new
   // ones.
   if (activites != null)
   {
       activities.ForEach(a =>
                    {
                        trip.Activities.Add(a);
                    });
   }

   context.Trips.Add(trip);
   context.SaveChanges();<br><br>

通过执行此操作,我希望EF更新所有相关的实体(除了活动,因为它有固定的条目,必须保持不变),即Trip和连接表自动但不起作用:创建一个新的旅程联接表中的更多条目(唯一有效的是实体活动保持不变)。

如何实现这一目标?我花了很多时间试图这样做但没有成功......

提前致谢。

编辑:
我删除了一行:
      context.Trips.Add(跳闸);

现在的结果是:
-Entity Trip已正确更新,未添加任何新记录,这是好的 - 实体活动保持不变,这是好的 - 加入表:更新当前行程的旧记录不会更新,而是为当前行程插入新记录,这些记录不正确。

2 个答案:

答案 0 :(得分:3)

我使用了一种不同的方法来处理我遇到的类似场景,这种方法适用于Detached Entities。我最后通过比较GUI(分离实体)值和数据库值来找出添加了哪些实体以及删除了哪些实体。这是我使用的示例代码。游戏中的实体是 RelayConfig StandardContact ,它们有很多关系

    public void Update(RelayConfig relayConfig, List<StandardContact> exposedContacts) {
        RelayConfig dbRelayConfig = context.RelayConfigs.Include(r => r.StandardContacts)
                                           .Where(r => r.Id == relayConfig.Id).SingleOrDefault();
        context.Entry<RelayConfig> (dbRelayConfig).CurrentValues.SetValues(relayConfig);

        List<StandardContact> addedExposedContacts = 
            exposedContacts.Where(c1 => !dbRelayConfig.StandardContacts.Any(c2 => c1.Id == c2.Id)).ToList();
        List<StandardContact> deletedExposedContacts = 
            dbRelayConfig.StandardContacts.Where(c1 => !exposedContacts.Any(c2 => c2.Id == c1.Id)).ToList();

        StandardContact dbExposedContact = null;
        addedExposedContacts.ForEach(exposedContact => {
            dbExposedContact = context.StandardContacts.SingleOrDefault(sc => sc.Id == exposedContact.Id);
            dbRelayConfig.StandardContacts.Add(dbExposedContact);
        });
        deletedExposedContacts.ForEach(exposedContact => { dbRelayConfig.StandardContacts.Remove(exposedContact);});

答案 1 :(得分:0)

您将使用类似的东西。假设您将从UI获取相关对象,并且您将在数据库中更新相同的对象,则可以使用以下某些内容。

 context.Products.Attach(product);
            context.ObjectStateManager.ChangeObjectState(product, System.Data.EntityState.Modified);
            context.ObjectStateManager.ChangeObjectState(product.ProductDescription, System.Data.EntityState.Modified);
            context.ObjectStateManager.ChangeObjectState(product.ProductModel, System.Data.EntityState.Modified);
            context.SaveChanges();

正如您在此处所看到的,我们将EntityState设置为Modified,这暗示EF也会对相关表执行更新。

请回复您的查询或您在此实施中可能遇到的任何问题。