在Entity Framework 6中更新多对多导航属性,未保存更改

Jef*_*eff 9 .net c# database sql-server entity-framework

我现在已经把头发拉了大约两天,因为每当我向现有实体添加多对多实体时,我根本无法获得EF来保存更改.

我的结构很简单:

  • 我有一个名为的表Person,它有一个ID(主要,身份)和一些其他字符串字段

  • 一个名为KeywordID(主,身份)和一个名为的字符串字段的表Value

  • 和a PersonKeywordRelation,有a PersonId和a KeywordId字段

当我(第一数据库)生成我的实体,我得到的一类Person,有ICollection<Keyword>-所有的好,按预期工作.

当我尝试Person使用修改后的关键字列表保存现有内容时,会出现问题.只保存标量属性(字符串),而不是我的关键字!

  • 我已经尝试禁用延迟加载,没有效果.
  • 我尝试再次从数据库中加载每个单独的关键字,没有效果.
  • 我尝试将所有关键字加载到上下文中以查看是否有助于EF检测更改,但事实并非如此.

我很确定我不是唯一一个遇到这个问题的人,(事实上我完全确定,因为我已经在这里看过几个问题,在同一个主题上,但我找不到合适的答案. ..),主要是针对旧版本的EF,这是另一个很好的理由,为什么我开始了另一个问题:没有任何改变可以解决这个问题?

这是我的代码,用于更新(和创建)人员.您会注意到我尝试相应地进行EF保存更改.

    public void SavePersons(IList<Person> persons)
    {
        // Create a EF Context
        using (var ctx = new MyDbEntities())
        {
            foreach (var person in persons)
            {
                // Attach
                ctx.Persons.Attach(person);

                // Insert or update?
                ctx.Entry(person).State = person.Id == 0 ? EntityState.Added : EntityState.Modified;

                // Get current keywords before clearing from entity
                var keywords = new List<Keyword>(person.Keywords);

                // Clear keywords from entity, so we can add fresh ones, hopefully
                // EF will have an easier time handling this..
                person.Keywords.Clear();

                // Add keywords
                keywords.ForEach(kw =>
                {
                    ctx.Keywords.Attach(kw);
                    ctx.Entry(kw).State = EntityState.Modified;
                    person.Keywords.Add(kw);
                });            
            }

            // Save
            ctx.SaveChanges();
        }
    }
Run Code Online (Sandbox Code Playgroud)

Jef*_*eff 12

终于..最后我可以休息了!我找到了解决方案!它不是一个漂亮的,但它的工作原理!

这是代码共享是关怀.

这绝对是我最后一次使用Entity Framework.造成更多的痛苦和痛苦.

    public void SavePersons(IList<Person> persons)
    {
        // Create a EF Context
        using (var ctx = new MyDbEntities())
        {
            // Iterate
            foreach (var person in persons)
            {
                // Get current keywords
                var keywords = new List<Keyword>(person.Keywords).ToList();

                // Fetch Person from DB (if its not a NEW entry). Must use Include, else it's not working.
                var newPerson = ctx.Persons
                                       .Include("Keywords")
                                       .FirstOrDefault(s => s.Id == person.Id) ?? person;

                // Clear keywords of the object, else EF will INSERT them.. Silly.
                newPerson.Keywords.Clear();

                // Insert or update?
                ctx.Entry(newPerson).State = newPerson.Id == 0 ? EntityState.Added : EntityState.Modified;

                // Apply new scalar values
                if(newPerson.Id != 0)
                {
                    person.Id = newPerson.Id;
                    ctx.Entry(newPerson).CurrentValues.SetValues(person);

                }

                // Iterate through all keywords
                foreach (var kw in ctx.Keywords)
                {
                    // If the current kw exists in OUR list, add it
                    // - if not, remove the relation from the DB.
                    if (keywords.Any(k => k.Id == kw.Id))
                    {
                        //ctx.Entry(kw).State = EntityState.Unchanged;
                        ctx.Keywords.Attach(kw);
                        newPerson.Keywords.Add(kw);
                    }
                    else
                        newPerson.Keywords.Remove(kw);
                }
            }

            // Save
            ctx.SaveChanges();

        }
    }
Run Code Online (Sandbox Code Playgroud)