views:

324

answers:

3

I have a table, say STUDENTS, that is related one-to-many to another table, CLASSES. I created an ASP.Net form to take input of a new student, including selection of one of the classes from a combo box. This is a small but multi-tier app, and I have started using the entity framework. So the EF generated classes for both those tables. On Submit, I am building a STUDENT object and handing it off to my Data controller for inserts, updates, etc.

In the STUDENTS table I have a CLASSID that's a FK to the CLASSES table. Back in the day, when I would do the insert to STUDENTS I would take the SelectedValue from the combo box and stick that into the ClassId field. However, with the EF, the STUDENT object doesn't have this ID field. Instead it has a CLASS field, which is a full-on instance of that class. When the new STUDENT object is built, that CLASS field is null. I want to populate it with the class the user chose in the combo.

I can't leave it null, and I can't just put the ID in there. I tried doing a retrieve of that class record and using that, but I get an error that I can't use the same object with two different contexts. What am I really supposed to be doing here?

+1  A: 

You can set EntityKey property of ClassReference:

Student.ClassReference.EntityKey = new EntityKey("myModel.ClassSet", "ID", classId);

EDIT

This is how to add student (I can't check it now, but it should work):

newStudent.BClassReference.EntityKey = new EntityKey("FormsEntities.BClasses", "BClassId", 13);

FormsEntities fe = new FormsEntities();
fe.AddToStudents(newStudent);
fe.SaveChanges();
LukLed
Just wanted to add that in EF4 the FK Id will be exposed and you don't have to use EntityKey.
jfar
LukLed, your method worked for me. I like this method because it doesn't require me to go back to the db to get a complete record. I already know the PK, I just want to use that. I must admit I don't know what exactly is happening in your code. Before, I tried to initialize the newStudent.BClass object and then add a new entity key, which didn't work. This property that adds the word "Reference" on the end of the object name seems to get the job done, regardless of whether the BClass property is null. Also, as in the other solution from Craig, it all has to happen with ONE context.
Mike at KBS
EntityReference is used to operate on navigation properties that are not yet loaded. You should also look at IsLoaded property and Load() method that is used to get Entity from DB: http://msdn.microsoft.com/en-us/library/bb297956.aspx
LukLed
A: 

I had to do some research on the EntityKey property, and then tried to get this to work but I'm getting various kinds of errors. Basically, I create a new Student object and fill in all the values. Then I do this (I'm using a constant here for testing purposes):

BClass cls = new BClass();
cls.EntityKey = new EntityKey("FormsEntities.BClasses", "BClassId", 13);
newStudent.BClass = cls;
cls.BClassId = 13;

FormsEntities fe = new FormsEntities();
fe.Attach(newStudent.BClass);
fe.AddToStudents(newStudent);
fe.SaveChanges();

Earlier, I just tried to SaveChanges() but then I got an error saying there was already a key so I needed to use Attach(). So I added the Attach() line above and now I'm getting an error that says "An object with the same key already exists in the ObjectStateManager. The existing object is in the Unchanged state. An object can only be added to the ObjectStateManager again if it is in the added state."

Honestly, why is something so simple, so difficult? I've wasted many hours on this, when all I used to have to do is put the integer right in there.

Mike at KBS
Look at EDIT of my answer.
LukLed
+1  A: 

How about start by doing things the easy way?

using (var fe = new FormsEntities())
{
    newStudent.BClass = fe.BClasses.Where(bc => bc.BClassId == 13).First();
    fe.AddToStudents(newStudent);
    fe.SaveChanges();
}

Don't muck around with EntityKeys until you get the basics working. I think that "optimizing" a save is largely a waste of time.

Craig Stuntz
I tried this early on, using different syntax, where I retrieved it and put it into the newStudent object. When I tried to save it, I got an exception that the object was already attached to a different context. I'll try it again using your syntax, perhaps I'll have better luck. I don't know about "optimizing" the save; I just want to PERFORM the save.
Mike at KBS
You were probably using > 1 context (`FormsEntries` instance), then. I suggest using only one at a time whenever possible. Makes things much simpler.
Craig Stuntz
Craig, your method worked. I think I figured out why mine didn't. I had the same idea, but I was doing the GETs in a different function, for separation reasons. When I did this I used a brand new context. So I'd go get the BClass using "GetClass(id)" and then call a different function, with a different context, to save the Student. I'd get "An entity object cannot be referenced by multiple instances of IEntityChangeTracker." When I use your syntax, or even mine, all in the same place with the same context (FormsEntities fe), everything works fine. Thanks for your help.
Mike at KBS