C# 无法定义两个对象之间的关系,因为它们附着到不同的ObjectContext对象

C# 无法定义两个对象之间的关系,因为它们附着到不同的ObjectContext对象,c#,.net,exception,entity-framework-4,C#,.net,Exception,Entity Framework 4,我已经阅读了一些与此特定错误消息有关的问题/答案,但我不太了解适当的解决方案 我已经读过很多次了,你应该创建EF4上下文,使用它,然后处理它。在整个应用程序中,我使用不同的上下文对象到处加载实体,然后最终希望将这些实体关联在一起 我创建了一个简单的控制台应用程序,它很容易导致错误。非常简单的模型用图表表示,后面是代码 如何让两个不同的实体共享相同的上下文?我真的需要创建一个新的上下文,再次加载这两个实体(即使我已经有了它们),只是为了关联它们并保存它们吗 如果我只是错过了一个已经存在的适当问题/

我已经阅读了一些与此特定错误消息有关的问题/答案,但我不太了解适当的解决方案

我已经读过很多次了,你应该创建EF4上下文,使用它,然后处理它。在整个应用程序中,我使用不同的上下文对象到处加载实体,然后最终希望将这些实体关联在一起

我创建了一个简单的控制台应用程序,它很容易导致错误。非常简单的模型用图表表示,后面是代码

如何让两个不同的实体共享相同的上下文?我真的需要创建一个新的上下文,再次加载这两个实体(即使我已经有了它们),只是为了关联它们并保存它们吗

如果我只是错过了一个已经存在的适当问题/答案,请给我指出正确的地方

internal class Program {

    private static void Main(string[] args) {
        DeleteAllEntities();
        CreateInitialEntities();
        Owner o = LoadOwner();
        Child c = LoadChild();
        AssociateAndSave(o, c);
    }

    private static void AssociateAndSave(Owner o, Child c) {
        using (var context = new ModelEntities()) {
            // Exception occurs on the following line.
            o.Children.Add(c);
            context.Attach(o);
            context.SaveChanges();
        }
    }

    private static Owner LoadOwner() {
        using (var context = new ModelEntities()) {
            return ((from o in context.Owners
                     select o).First());
        }
    }

    private static Child LoadChild() {
        using (var context = new ModelEntities()) {
            return ((from c in context.Children
                     select c).First());
        }
    }

    private static void CreateInitialEntities() {
        using (var context = new ModelEntities()) {
            Owner owner = new Owner();
            Child child = new Child();
            context.Owners.AddObject(owner);
            context.Children.AddObject(child);
            context.SaveChanges();
        }
    }

    private static void DeleteAllEntities() {
        using (var context = new ModelEntities()) {
            List<Child> children = (from c in context.Children
                                    select c).ToList();
            foreach (var c in children)
                context.Children.DeleteObject(c);
            List<Owner> owners = (from o in context.Owners
                                  select o).ToList();
            foreach (var o in owners)
                context.Owners.DeleteObject(o);
            context.SaveChanges();
        }
    }
}

内部类程序{
私有静态void Main(字符串[]args){
deleteAllenties();
CreateInitialEntities();
所有者o=LoadOwner();
Child c=LoadChild();
协会和储蓄(o,c);
}
私有静态无效关联和保存(所有者o,子c){
使用(var context=new modeleentities()){
//下一行出现异常。
o、 添加(c);
上下文。附上(o);
SaveChanges();
}
}
私有静态所有者LoadOwner(){
使用(var context=new modeleentities()){
return((来自context.owner中的o)
选择o.First());
}
}
私有静态子LoadChild(){
使用(var context=new modeleentities()){
return((在context.Children中来自c
选择c.First());
}
}
私有静态void CreateInitialEntities(){
使用(var context=new modeleentities()){
所有者=新所有者();
子项=新子项();
context.owner.AddObject(所有者);
context.Children.AddObject(child);
SaveChanges();
}
}
私有静态void deleteAllenties(){
使用(var context=new modeleentities()){
List children=(来自context.children中的c
选择c.ToList();
foreach(儿童中的var c)
context.Children.DeleteObject(c);
列出所有者=(从上下文中的o开始)。所有者
选择o.ToList();
foreach(所有者中的var o)
context.Owners.DeleteObject(o);
SaveChanges();
}
}
}

不能从一个上下文中删除对象,因为每个上下文都单独跟踪其对象

一个想法是为每个方法提供一个上下文类型的参数,以便在相同的上下文中进行操作

例:


如果您想做得更好,我建议您寻找依赖注入,因为它在ORM中非常有用。

您应该在同一上下文中获得对子对象和所有者对象的引用。一种方法是获取ID,然后将其作为参数传递给
AssociateAndSave(intOID,intCID)
方法

然后,在同一上下文中检索对对象的引用,并制作附件

private static void Main(string[] args)
{
    DeleteAllEntities();
    CreateInitialEntities();
    int oId = LoadOwnerId();
    int cId = LoadChildId();
    AssociateAndSave(oId, cId);
}

private static int LoadOwnerId()
{
    using (var context = new ModelEntities())
    {
        return (from o in context.Owners
                select o).First().Id;
    }
}

private static int LoadChildId()
{
    using (var context = new ModelEntities())
    {
        return (from c in context.Children
                select c).First().Id;
    }
}

private static void AssociateAndSave(int oId, int cId)
{
    using (var context = new ModelEntities())
    {
        var owner = (from o in context.Owners
                        select o).FirstOrDefault(o => o.ID == oId);
        var child = (from o in context.Children
                        select o).FirstOrDefault(c => c.ID == cId);

        owner.Children.Add(child);
        context.Attach(owner);
        context.SaveChanges();
    }
}

隐马尔可夫模型。。只需调用
context.Attach(o);上下文。附上(c)防止出现错误。但是,当我在实际应用程序中尝试这一点时,我发现ObjectStateManager中已经存在一个具有相同密钥的对象。ObjectStateManager无法跟踪具有相同键的多个对象
,即使实体是以与本例类似的方式加载的……我过去一直保持上下文处于活动状态,以便可以执行此操作,但我一遍又一遍地读到,您应该在需要时只将上下文保留很短的时间。在我的应用程序中,上下文可能会被打开5分钟,甚至一个小时。这实际上取决于用户打开窗口的时间。另外-你说每个上下文分别跟踪其实体,但是上下文被处理掉了(我所有的操作都是在
中使用
块)。实际上,我一开始就是这样做的,但我觉得在数据库中查询我以前从数据库中加载的实体有点浪费。我决定在这个问题上使用两个答案的一部分,但不幸的是,我无法将它们都标记为答案:)任何搜索到这一点的人也应该看到。
private static void Main(string[] args)
{
    DeleteAllEntities();
    CreateInitialEntities();
    int oId = LoadOwnerId();
    int cId = LoadChildId();
    AssociateAndSave(oId, cId);
}

private static int LoadOwnerId()
{
    using (var context = new ModelEntities())
    {
        return (from o in context.Owners
                select o).First().Id;
    }
}

private static int LoadChildId()
{
    using (var context = new ModelEntities())
    {
        return (from c in context.Children
                select c).First().Id;
    }
}

private static void AssociateAndSave(int oId, int cId)
{
    using (var context = new ModelEntities())
    {
        var owner = (from o in context.Owners
                        select o).FirstOrDefault(o => o.ID == oId);
        var child = (from o in context.Children
                        select o).FirstOrDefault(c => c.ID == cId);

        owner.Children.Add(child);
        context.Attach(owner);
        context.SaveChanges();
    }
}