C# 正在更新实体框架6中的多对多导航属性,未保存更改

C# 正在更新实体框架6中的多对多导航属性,未保存更改,c#,.net,sql-server,database,entity-framework,C#,.net,Sql Server,Database,Entity Framework,我已经花了大约2天的时间,因为每当我向现有实体添加多对多实体时,我根本无法让EF保存更改 我的结构非常简单: 我有一个名为Person的表,它有一个ID(Primary,identity)和一些其他字符串字段 一个名为Keyword的表,带有一个ID(主ID、标识)和一个名为Value的字符串字段 以及PersonKeywordRelation,带有PersonId,以及KeywordId字段 当我生成实体(首先是数据库)时,我得到一个类Person,带有ICollection——一切正常,

我已经花了大约2天的时间,因为每当我向现有实体添加多对多实体时,我根本无法让EF保存更改

我的结构非常简单:

  • 我有一个名为
    Person
    的表,它有一个ID(Primary,identity)和一些其他字符串字段

  • 一个名为
    Keyword
    的表,带有一个ID(主ID、标识)和一个名为
    Value的字符串字段

  • 以及
    PersonKeywordRelation
    ,带有
    PersonId
    ,以及
    KeywordId
    字段

当我生成实体(首先是数据库)时,我得到一个类
Person
,带有
ICollection
——一切正常,工作正常

当我试图用修改过的关键字列表保存现有的
人员时,问题就出现了。只保存标量属性(字符串),不保存我的关键字

  • 我已尝试禁用延迟加载,但没有效果
  • 我再次尝试从数据库中加载每个关键字,没有效果
  • 我尝试将所有关键字加载到上下文中,看看这是否有助于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();
        }
    }
public void SavePersons(IList persons)
{
//创建EF上下文
使用(var ctx=new MyDbEntities())
{
foreach(var个人对个人)
{
//附加
ctx.人员。附件(人员);
//插入还是更新?
ctx.Entry(person.State=person.Id==0?EntityState.Added:EntityState.Modified;
//在从实体中清除之前获取当前关键字
var关键字=新列表(个人关键字);
//从实体中清除关键字,以便我们可以添加新的关键字,希望如此
//EF将更容易处理此问题。。
person.Keywords.Clear();
//添加关键字
关键词.ForEach(kw=>
{
ctx.关键词.附件(千瓦);
ctx.Entry(kw.State=EntityState.Modified;
人.关键词.加(千瓦);
});            
}
//拯救
ctx.SaveChanges();
}
}
尝试添加.ToList()

var keywords = new List<Keyword>(person.Keywords).ToList();//generate list sepereate from .Keywords
var keywords=新列表(person.keywords).ToList()//生成列表separate from.Keywords

我怀疑您的关键字列表从未填充过,因为您在水合之前清除了它。

因此以下内容未经测试,但在您修复我的错误之后;)希望它能成功。我不知道代码的其余部分,所以我选择创建输入数据的克隆,并按特定顺序将对象附加到上下文中

编辑:重命名方法

    // get unique list of Keywords from all Persons
    private List<Keyword> getUniqueKeywords(IEnumerable<Person> oxygenThiefs) {
        var result = new List<Keyword>();

        foreach (var thief in oxygenThiefs) {
            foreach (var keyword in thief.Keywords) {
                if (!result.Contains(keyword)) {
                    result.Add(keyword);
                }
            }
        }

        return result;
    }

    // shallow clone of Person
    private Person clonePerson(Person target) {

        return new Person {
            Id = target.Id,
            Name = target.Name,
            ..
            ..

        };
    }

    public void SavePersons(IList<Person> persons) {
        // Create a EF Context
        using (var ctx = new MyDbEntities()) {

            // add all Keywords to the Context so that they are tracked
            foreach (var keyword in getUniqueKeywords(persons)) {
                ctx.Keywords.Attach(keyword);
                // if value of Keyword has actually changed then uncomment line
                // ctx.Entry(keyword).State = EntityState.Modified
            }

            foreach (var person in persons) {

                // hehe
                var shallowPerson = clonePerson(person);

                // Attach Person
                ctx.Persons.Attach(shallowPerson);

                // Establish relationship (however shallow and meaningless)
                foreach (var keyword in person.Keywords) {
                    shallowPerson.Keywords.Add(keyword);
                }

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

            }

            // Save
            ctx.SaveChanges();
        }
    }
//从所有人员获取唯一的关键字列表
私有列表getUniqueKeywords(IEnumerable oxygenThiefs){
var result=新列表();
foreach(氧气中的var小偷){
foreach(小偷中的var关键字。关键字){
如果(!result.Contains(关键字)){
结果.添加(关键字);
}
}
}
返回结果;
}
//人的浅克隆
私人clonePerson(个人目标){
换人{
Id=target.Id,
Name=target.Name,
..
..
};
}
公共储蓄人(IList人){
//创建EF上下文
使用(var ctx=new MyDbEntities()){
//将所有关键字添加到上下文中,以便跟踪它们
foreach(getUniqueKeywords(persons)中的var关键字){
ctx.Keywords.Attach(关键字);
//若关键字的值实际已更改,则取消注释行
//ctx.Entry(关键字).State=EntityState.Modified
}
foreach(var个人对个人){
//呵呵
var shallowPerson=clonePerson(个人);
//随员
ctx.人员附件(浅层人员);
//建立关系(无论多么肤浅和毫无意义)
foreach(var关键字在person.Keywords中){
shallowPerson.Keywords.Add(关键字);
}
//插入还是更新?
ctx.Entry(shallwperson).State=person.Id==0?EntityState.Added:EntityState.Modified;
}
//拯救
ctx.SaveChanges();
}
}

最后。。我终于可以休息了!我找到了解决办法!这不是一个漂亮的,但它的工作

代码共享就是关心

这肯定是我最后一次使用实体框架。导致更多的痛苦和痛苦,而不是好的

    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();

        }
    }
public void SavePersons(IList persons)
{
//创建EF上下文
使用(var ctx=new MyDbEntities())
{
//迭代
foreach(var个人对个人)
{
//获取当前关键字
var keywords=新列表(person.keywords).ToList();
//从数据库中提取人员(如果不是新条目)。必须使用Include,否则无法工作。
var newPerson=ctx.Persons
.包括(“关键字”)