如何使用Entity Framework关联来自多个上下文的对象

14

我对实体框架非常陌生,请耐心等待我的学习...

我如何将来自不同上下文的两个对象关联在一起?

以下示例会引发以下异常:

System.InvalidOperationException:由于它们附加到不同的ObjectContext对象,因此无法定义两个对象之间的关系。

void MyFunction()
{
    using (TCPSEntities model = new TCPSEntities())
    {
        EmployeeRoles er = model.EmployeeRoles.First(p=>p.EmployeeId == 123);
        er.Roles = GetDefaultRole();
        model.SaveChanges();
     }
}

private static Roles GetDefaultRole()
{
    Roles r = null;
    using (TCPSEntities model = new TCPSEntities())
    {
        r = model.Roles.First(p => p.RoleId == 1);
    }
    return r;
}

因为我们在ASP.NET应用程序中使用Entity Framework,所以不能使用一个上下文。


你为什么将数据上下文类型命名为TCPSEntities,并将数据上下文对象命名为model?你可以考虑不使用new,而是将预先构建的数据上下文或数据上下文工厂传递给函数。你还可以考虑使用Enumerable.SingleOrDefault而不是Enumerable.First - yfeldblum
4个回答

11

您将需要使用相同的上下文(您可以将上下文传递给getdefaultrole方法)或重新考虑关系并扩展实体。

编辑:想要补充说明这是针对所提供的示例,使用asp.net将要求您充分考虑上下文和关系设计。

您可以简单地传递上下文.. 例如:

void MyFunction()
{
    using (TCPSEntities model = new TCPSEntities())
    {
        EmployeeRoles er = model.EmployeeRoles.First(p=>p.EmployeeId == 123);
        er.Roles = GetDefaultRole(model);
        model.SaveChanges();
     }

}

private static Roles GetDefaultRole(TCPSEntities model)
{
    Roles r = null;
    r = model.Roles.First(p => p.RoleId == 1);
    return r;
}

4

在这里您可以采用另一种方法,即将对象从一个上下文中分离,然后附加到另一个上下文中。虽然这有点不正规,并且可能在您的情况下无法奏效,但也许是一个选择。

    public void GuestUserTest()
    {
        SlideLincEntities ctx1 = new SlideLincEntities();
        GuestUser user = GuestUser.CreateGuestUser();
        user.UserName = "Something";
        ctx1.AddToUser(user);
        ctx1.SaveChanges();

        SlideLincEntities ctx2 = new SlideLincEntities();
        ctx1.Detach(user);
        user.UserName = "Something Else";
        ctx2.Attach(user);
        ctx2.SaveChanges();
    }

2

1
旧帖但是好的参考链接...现在已经在http://www.ef-faq.org上得到维护。 - Craig
现在将http://social.technet.microsoft.com/wiki/contents/articles/entity-framework-faq.aspx制作出来。 - Kit

2
据我所了解,您希望尽可能少地实例化模型(通过 "new XXXXEntities()" 代码部分)。根据微软的说法(http://msdn.microsoft.com/en-us/library/cc853327.aspx),这会对性能造成相当大的影响。因此,将其包装在 using() 结构中并不是一个好主意。在我的项目中,我通过静态方法访问它,该方法始终提供上下文的相同实例。
    private static PledgeManagerEntities pledgesEntities;
    public static PledgeManagerEntities PledgeManagerEntities
    {
        get 
        {
            if (pledgesEntities == null)
            {
                pledgesEntities = new PledgeManagerEntities();
            }
            return pledgesEntities; 
        }
        set { pledgesEntities = value; }
    }

然后我像这样检索它:

    private PledgeManagerEntities entities = Data.PledgeManagerEntities;

这被称为单例模式。 - Mathias Lykkegaard Lorenzen
1
几件事情:(1)我认为你在做这件事情时必须小心,因为上下文将跟踪任何已加载的实体,导致实例变得庞大。(2)您引用的文章还指出:“在大多数情况下,您应该在using语句中创建一个ObjectContext实例”。(3)如果一次SaveChanges()调用失败,则所有后续调用都可能失败,除非您分离失败的实体。如果有多个调用者使用同一个上下文,则可能会陷入混乱。(4)ObjectContext不是线程安全的。 - Tom Haigh
这对于Web应用程序来说绝对是不安全的,而且性能提升微不足道。除非特殊情况,通常您应该为每个业务操作使用一个上下文。这通常意味着在每个页面/窗口中使用一个上下文。 - Monstieur
@Kurian - 对于一个ASP.NET应用程序,你是完全正确的。当我三年前回答这个问题时,我怀疑我没有仔细阅读它三年前才意识到这一点:-)。 - Ken Smith

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接