Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用多对多关系更新断开连接的实体_C#_Entity Framework_Ef Code First_Many To Many_Dbcontext - Fatal编程技术网

C# 使用多对多关系更新断开连接的实体

C# 使用多对多关系更新断开连接的实体,c#,entity-framework,ef-code-first,many-to-many,dbcontext,C#,Entity Framework,Ef Code First,Many To Many,Dbcontext,假设我在实体框架代码第一次设置中有以下模型类: public class Person { public int Id { get; set; } public string Name { get; set; } public virtual ICollection<Team> Teams { get; set; } } public class Team { public int Id { get; set; } public strin

假设我在实体框架代码第一次设置中有以下模型类:

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Team> Teams { get; set; }
}

public class Team
{
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Person> People { get; set; }
}
但是团队集合只是被忽略了。我也尝试过其他各种方法,但似乎没有什么能完全满足我的要求。谢谢你的帮助

编辑:

因此,我可以从数据库中获取人员和团队,更新他们,然后提交更改:

using (var context = new TestContext())
{
    var dbPerson = context.People.Find(person.Id);
    dbPerson.Name = person.Name;
    dbPerson.Teams.Clear();
    foreach (var id in person.Teams.Select(x => x.Id))
    {
        var team = context.Teams.Find(id);
        dbPerson.Teams.Add(team);
    }

    context.SaveChanges();
}

然而,如果一个人是一个复杂的实体,这是一种痛苦。我知道我可以使用Automapper或其他工具使事情变得更简单,但如果无法保存原始的person对象,这似乎是一种耻辱,一般的方法是从数据库中获取
团队
,并将其添加到
人员的
团队
集合中,而不必获取一个新的团队并复制所有的属性。设置EntityState.Modified只影响标量属性,而不影响导航属性。

尝试先选择现有实体,然后将团队附加到person对象的团队集合

类似这样:(语法可能不完全正确)


这就是EF s**ks的位置。对于断开连接的场景,效率非常低。加载更新/删除和重新附加更新的数据时,不能仅将更新的实体附加到上下文,因为上下文中可能已经存在具有相同键的实体,在这种情况下,EF将抛出。需要做的是检查具有相同密钥的实体是否已经在上下文中,并相应地附加或更新。使用多对多关系子对象更新实体更糟糕。删除已删除的子对象是从子对象的实体集中删除的,而不是从引用属性中删除,这非常混乱。

您可以使用“附加”方法。试试这个:

using (var context = new TestContext())
{
    context.People.Attach(person);

    //i'm not sure if this foreach is necessary, you can try without it to see if it works
    foreach (var team in person.Teams)
    {
        context.Teams.Attach(team);
    }

    context.Entry(person).State = EntityState.Modified;

    context.SaveChanges();
}

我没有测试这段代码,如果您有任何问题,请告诉我。

购买本身,这似乎不起作用:将从db获取的团队添加到非代理的人员仍然不会更新TeamPersons表。工作是从数据库中同时获取团队和人员(因此人员是代理),但是您必须更新此获取的人员以匹配被保存的人员……啊,您是对的(应该读得更好)。编辑后:您可以使用
DbContext.Entry(dbPerson).CurrentValues.SetValues(person)
。谢谢,这很有用-我不知道CurrentValues.setValuesHanks,但是我必须从我想要保存的原始人更新这个新人(请参见我的编辑)-我希望有另一种方法。好的,你是说断开连接的person对象有很多更改?可能是的:我想知道从断开连接的person对象更新db的最佳方法,但不知道该对象的哪些属性已更改。
using (var context = new TestContext())
{
    var dbPerson = context.People.Find(person.Id);
    dbPerson.Name = person.Name;
    dbPerson.Teams.Clear();
    foreach (var id in person.Teams.Select(x => x.Id))
    {
        var team = context.Teams.Find(id);
        dbPerson.Teams.Add(team);
    }

    context.SaveChanges();
}
using (var context = new TestContext())
{
    var person = context.Persons.Where(f => f.Id == 1).FirstOrDefault();
    var team = context.Teams.Where(f => f.Id == 3).FirstOrDefault();

    person.Teams.Add(team);

    context.Entry(person).State = EntityState.Modified;
    context.SaveChanges();
}
using (var context = new TestContext())
{
    context.People.Attach(person);

    //i'm not sure if this foreach is necessary, you can try without it to see if it works
    foreach (var team in person.Teams)
    {
        context.Teams.Attach(team);
    }

    context.Entry(person).State = EntityState.Modified;

    context.SaveChanges();
}