8

I am new to EF 4 and this is what I have done so far:

  • Create an edmx file based on my database
  • Create a code generation for my objects (POCO). Now I have a model1.tt, when expanded I see al my classes
  • Create a repository for each class, based on IRepository

Now, I am working with two objects, A and B. Object A has a property of type B. In my winform I have a combo filled with objects of type B. When the save button is pressed, a new instance of class A is created and all the properties are set. The object B property is set as follows:

objectA.myObjectB = (objectB)cmbBObjects.selectedItem;

Then I create a repository for objectA and call the save method. In this save method I have this code±

public bool Save(ObjectA obj)
{
  using(MyContext context = new MyContext())
  {
    context.objectAs.AddObject(obj);
    context.SaveChanges();
  }
}

This code, does save a new entry to the database, but it is also creating a new record for object B! I don't want this, because object B already exists in the database! (I have selected this one from the combobox).

This is how I fill my combobox:

In the objectB repository:

public IList<ObjectB> GetAll()
{
    using(MyContext context = new MyContext())
    {
        IList<ObjectB> objects = context.objectBs.ToList();
        return objects;
    }
}

In my form:

ObjectBRepository rep = new ObjectBRepository();
IList<ObjectB> objects = rep.GetAll;

cmbBObjects.Datasource = objects;
// etc..

So my question is, what do I have to do to save object A without creating a new record for objectB?

2 Answers 2

20

If you don't want insert objectB you must inform EF about it. When you call context.objectAs.AddObject(obj) for objectA you are saying: I want to insert objectA and all its dependencies. But obviously you don't want to save dependecies so you must either:

  • Load objectB from DB before adding it to objectA. In such case EF will know that objectB is existing object and it will not insert it again.
  • Attach objectB to context before adding it to objectA. ObjectB will be handled as existing but unchanged.
  • Set the state of objectB after inserting objectA. You can do that by calling: context.ObjectStateManager.ChangeObjectState(objectB, EntityState.Unchanged)

Example of the fist suggestion:

var id = objectB.Id;
objectA.myObjectB = context.ObjectBs.SingleOrDefault(o => o.Id == id);

Example of the second suggestion:

context.ObjectBs.Attach(objectB);
objectA.myObjectB = objectB;

Example of the third suggestion:

objectA.myObjectB = objectB;
context.ObjectAs.AddObject(objectA);
context.ObjectStateManager.ChangeObjectState(objectB, EntityState.Unchanged);
Sign up to request clarification or add additional context in comments.

15 Comments

Thank you. I don't understand suggestion 1. The second suggestion: In the repository of objectA, do something like: var obj = context.ObjectB.where(b=> b.Id == objectA.myObjectB.Id).firstOrDefault(); context.ObjectA.Attach(obj); Is this correct?
@LadislavMrnka: Exactly, all possible options, and i suppose second option best one for above example. +1
I've tried your second solution, but slightly different. In my Save method of my ObjectA repository I had this: context.objectBs.Attach(objectA.myObjectB); context.objectAs.AddObject(objectA); context.SaveChanges(); But here I got a key alreaydy exists exception at line context.objectAs.AddObject(objectA); Why was that?
You must Attach objectB before you assing it to objectA otherwise you will attach both objects and you will not be able to add objectA.
@Martijn: You should attach objectB to context after you get it from dataContext and only objectB not objectA.
|
1

I suppose that problem in following row:

objectA.myObjectB = (objectB)cmbBObjects.selectedItem;

Because of result (objectB)cmbBObjects.selectedItem detached from datacontext entity framework create new instance. Instead this you can:

1.Assign objectB id to objectA

var b = (objectB)cmbBObjects.selectedItem;
objectA.myObjectBId = b.Id;

2.Or load objectB from dataContext and than assign to objectA:

var b = (objectB)cmbBObjects.selectedItem;
var dcB = context.ObjectBs.Single(x=> x.Id == b.Id);
objectA.myObjectB = dcB;

Just try my suggestions and come back with results, because i don't know exactly.

Hope this help.

2 Comments

objectA does not have a objectB id directly, this must be set as follows (I suppose) objectA..myObjectB.Id = b.Id But, I think this will throw an argumentNull exception, because the .myObjectB property is not set. The second solution: I don't think I want my context in the winform, I'd like to keep that object in my repositories.
@Martijn: Okay, than you should go second way suggested by me(load objectB from dataContext and assign to objectA).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.