1_bug
1_bug

Reputation: 5717

C# & EF 4 - Update related object in database

My classes (and tables):

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

    public virtual C CField {get; set;}
}

class B {
    public int Id {get; set;}
    public string Name {get; set;}
    public DateTime Date {get; set;}

    public virtual C CField {get; set;}
}

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

class D {
    public int Id {get; set;}
    public string Title {get; set;}

    public virtual A AField {get; set;}
    public virtual B BField {get; set;}
}

I need update my D object. I use dependency injection so I can use repositories in controller:

A aObj = aService.GetAById(id);
B bObj = bService.GetBByName(name);
D dObj = new D()
{
    Title = "MyTitle",
    AField = aObj,
    BField = bObj
};
dService.Update(dObj);

In each class repository I just create context as private field:

private MyContext db = new MyContext();

and I use it in every method like:

var model = db.A.Where(x=>x.Id == id);
return model;

But it can't work because both classes A and B has field with C class so I still got excepted: An entity object cannot be referenced by multiple instances of IEntityChangeTracker when I call dService.Update(dObj) (second listing). I found that I should detach context in every method in each repositroy like this:

var model = db.A.Where(x=>x.Id == id);
db.Entry(model).State = System.Data.Entity.EntityState.Detached;
return model;

Exception was gone but now CField in aObj and bObj is always null and dObj.BField is not updated.

How can I fix that and what I'm doing wrong? I lost a few days for finding out what I should do: I even try remove private context field in repositories and in every method just use using(var db = new MyContext()) but then exception "An entity object cannot be referenced by multiple instances of IEntityChangeTracker" is back.

Upvotes: 0

Views: 92

Answers (1)

Szel
Szel

Reputation: 120

You can't mix entities from different contexts in EF. Use ids instead.

Update models:

class A {
    public int Id {get; set;}
    public string Name {get; set;}
    public int CFieldId {get; set;}
    public virtual C CField {get; set;}
}

class B {
    public int Id {get; set;}
    public string Name {get; set;}
    public DateTime Date {get; set;}
    public int CFieldId {get; set;}
    public virtual C CField {get; set;}
}

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

class D {
    public int Id {get; set;}
    public string Title {get; set;}
    public int AFieldId {get; set;}
    public int BFieldId {get; set;}
    public virtual A AField {get; set;}
    public virtual B BField {get; set;}
}

And in controller:

A aObj = aService.GetAById(id);
B bObj = bService.GetBByName(name);
D dObj = new D()
{
    Title = "MyTitle",
    AFieldId = aObj.Id,
    BFieldId = bObj.Id
};
dService.Update(dObj);

Upvotes: 1

Related Questions