14

I am very new to the entity framework, so please bear with me...

How can I relate two objects from different contexts together?

The example below throws the following exception:

System.InvalidOperationException: The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects.

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;
}

Using one context is not an option because we are using the EF in an ASP.NET application.

Hooked
  • 84,485
  • 43
  • 192
  • 261
Giovanni Galbo
  • 12,963
  • 13
  • 59
  • 78
  • Why did you name your data-context type `TCPSEntities`, and why did you name your data-context object `model`? And you might think about not using `new`, but either passing in a pre-constructed data-context or a data-context-factory to the function. You might also think about using `Enumerable.SingleOrDefault` instead of `Enumerable.First`. – yfeldblum May 03 '09 at 17:07

4 Answers4

11

You will have to use the same context (you can pass the context to the getdefaultrole method) or rethink the relationships and extend the entity.

EDIT: Wanted to add this was for the example provided, using asp.net will require you to fully think out your context and relationship designs.

You could simply pass the context.. IE:

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;
}
Quintin Robinson
  • 81,193
  • 14
  • 123
  • 132
4

Another approach that you could use here is to detach objects from one context, and then attach them to another context. That's a bit of a hack, and it may not work in your situation, but it might be an option.

    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();
    }
Ken Smith
  • 20,305
  • 15
  • 100
  • 147
2

Yep - working across 2 or more contexts is not supported in V1 of Entity Framework.

Just in case you haven't already found it, there is a good faq on EF at http://blogs.msdn.com/dsimmons/pages/entity-framework-faq.aspx

Eric Nelson
  • 328
  • 1
  • 3
  • 9
  • 1
    Old post but good reference link...it is now being maintained at http://www.ef-faq.org. – Craig Feb 22 '11 at 21:47
  • Make that http://social.technet.microsoft.com/wiki/contents/articles/entity-framework-faq.aspx now. – Kit Nov 11 '11 at 20:10
2

From what I understand, you want to instantiate your model (via the "new XXXXEntities()" bit) as rarely as possible. According to MS (http://msdn.microsoft.com/en-us/library/cc853327.aspx), that's a pretty substantial performance hit. So wrapping it in a using() structure isn't a good idea. What I've done in my projects is to access it through a static method that always provides the same instance of the context:

    private static PledgeManagerEntities pledgesEntities;
    public static PledgeManagerEntities PledgeManagerEntities
    {
        get 
        {
            if (pledgesEntities == null)
            {
                pledgesEntities = new PledgeManagerEntities();
            }
            return pledgesEntities; 
        }
        set { pledgesEntities = value; }
    }

And then I retrieve it like so:

    private PledgeManagerEntities entities = Data.PledgeManagerEntities;
Ken Smith
  • 20,305
  • 15
  • 100
  • 147
  • This is called the Singleton pattern. – Mathias Lykkegaard Lorenzen Oct 08 '11 at 20:52
  • 1
    A couple of things: (1) I thought that you had to be careful doing this because of the way that the context will track any entities that it has loaded causing the instance to grow large. (2) The article you reference also states: "In most cases, you should create an ObjectContext instance within a using statement". (3) If one call to SaveChanges() fails then all subsequent ones are likely to fail unless you detach the failing entities. If you have multiple callers using the same context then you may get in a mess. (4) ObjectContext is not threadsafe – Tom Haigh Jul 24 '12 at 11:03
  • This is absolutely unsafe for web applications and the performance gain is negligible. Except for special cases you should generally be using one context per business operation. This usually means using one context per page/window. – Monstieur Aug 01 '12 at 05:23
  • @Kurian - For an ASP.NET application, you're absolutely correct. When I answered the question three years ago, I doubt I had read it close enough three years ago to realize that :-). – Ken Smith Aug 01 '12 at 15:27