简体   繁体   English

实体框架多对多更新

[英]Entity Framework updating many to many

I am trying to find the suitable form of updating a many to many relationship but i am find some issues on it. 我正在尝试找到更新多对多关系的合适形式,但是我发现了一些问题。

The application is an asp.net mvc with simple injector(set up per context) 该应用程序是带有简单注入器的asp.net mvc(根据上下文设置)

I have an entity People which has an IEnumerable and also i have a entity Team which has an IEnumerable. 我有一个拥有IEnumerable的实体People,也有一个拥有IEnumerable的实体Team。

The People entity has some other fields like Description, Email, etc and in its View, there are some check boxes so the user can choose the Teams. 人员实体还有其他字段,如描述,电子邮件等,并且在其视图中有一些复选框,因此用户可以选择团队。

I had tried to search on the net for the best approach for updating a many to many relationship and all that i found was deleting everything in the third table that is created and then add the Teams again. 我曾尝试在网上搜索更新多对多关系的最佳方法,而我发现的所有内容就是删除已创建的第三张表中的所有内容,然后再次添加团队。

Under is what i am trying to do, but i am getting pk's already exists. 下面是我正在尝试做的事情,但是我正在获取PK已经存在。 I know it is happening because firstly i load the People entity with Find method(to remove the list of Teams inside a foreach) and after i try to Attach(when the error happens) the modified object to set it's State to Modified. 我知道它在发生,因为首先我使用Find方法加载People实体(以删除foreach内的团队列表),然后尝试附加(发生错误时)将修改后的对象设置为“已修改”,即状态为“已修改”。

        public override void Modify(People obj)
    {
        var ppl = SearchById(obj.Id);

        if (ppl.Teams.Count > 0)
        {
            foreach (var team in ppl.Teams.ToList())
            {
                ppl.Teams.Remove(team);
            }
        }

        var entry = lpcContext.Entry(obj);

        if (lpcContext.Entry(obj).State == EntityState.Detached)   
            dbSet.Attach(obj);            

        entry.State = EntityState.Modified;
    }

To air it out some things, i am using the Unit Of Work pattern, so i SaveChanges later. 为了说明问题,我使用工作单位模式,因此稍后保存更改。

Are there any other approach or i have to remove the Teams one by one, SaveChanges and after that, update the object and SaveChanges again? 还有其他方法吗,或者我必须一个接一个地删除团队,SaveChanges,然后再更新对象和SaveChanges?

Unfortunately, working with detached entities isnt that straight forward in EF (yet). 不幸的是,在EF中,与分离的实体一起工作并没有那么简单(到目前为止)。 Attach() in EF will work for connected entities only. EF中的Attach()仅适用于连接的实体。 That means if you load an object from DB, pass it on to a view (or page is asp.net). 这意味着,如果您从数据库加载对象,则将其传递到视图(或页面为asp.net)。 When you read the object back from that view/page, EF will not be tracking that object anymore. 当您从该视图/页面读回该对象时,EF将不再跟踪该对象。 If you now try to use Attach(), you will get an error that the key already exists in the DBContext. 如果现在尝试使用Attach(),则会收到错误消息,表明密钥已存在于DBContext中。 To workaround this, you need to find the entry and make changes to the entity using SetValues(). 若要解决此问题,您需要找到条目并使用SetValues()对实体进行更改。 Something like this: 像这样:

public virtual void Update(T entity)
        {
            DbEntityEntry dbEntityEntry = DbContext.Entry(entity);

            if (dbEntityEntry.State == EntityState.Detached)
            {
                var pkey = _dbset.Create().GetType().GetProperty("Id").GetValue(entity);//assuming Id is the key column
                var set = DbContext.Set<T>();
                T attachedEntity = set.Find(pkey);
                if (attachedEntity != null)
                {
                    var attachedEntry = DbContext.Entry(attachedEntity);
                    attachedEntry.CurrentValues.SetValues(entity);
                }                    
            }                
        }

Please note that this will ignore any nested objects. 请注意,这将忽略任何嵌套对象。 Hence, you should make DB trip, and compare the object returned from DB to find out if you should invoke Add, Update or Delete on each child object. 因此,您应该跳出数据库,并比较从数据库返回的对象,以确定是否应该在每个子对象上调用添加,更新或删除。 This is the best workaround I could find when working with disconnected objects in EF. 这是在EF中处理断开连接的对象时可以找到的最佳解决方法。 I guess nHibernate doesnt have this bug. 我猜nHibernate没有这个错误。 Last I read about this, Microsoft was going to work on this after EF 6.x. 最后我读到了有关此内容的信息,Microsoft将在EF 6.x之后对此进行处理。 So, we'll have to wait for this, I guess. 所以,我想我们必须等待。 Please go through the below article to understand the issue (and possible solutions) in length: 请仔细阅读以下文章,以了解该问题(以及可能的解决方案)的长度:

http://blog.maskalik.com/entity-framework/2013/12/23/entity-framework-updating-database-from-detached-objects/ http://blog.maskalik.com/entity-framework/2013/12/23/entity-framework-updating-database-from-detached-objects/

To talk about your specfic scenario, you should make a DB hit and find out if any new teams were selected or some existing team was dropped and call add or delete as appropriate by comparing the Team collection of People object returned by DB vs People object returned from view/page. 要谈论您的特定场景,您应该命中数据库,并通过比较DB返回的People对象与People对象返回的Team集合,来确定是否选择了任何新团队或是否删除了一些现有团队,并根据需要调用添加或删除。从视图/页面。 To update the People object itself, you can use the Update() as given above. 要更新People对象本身,可以使用上面提供的Update()。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM