views:

65

answers:

2

I have come across what appears to be very peculiar behaviour using entity framework 4.0.

I have a User entity, which has a Company (A Company has many Users).

If I do this, everything works as expected and I get a nice shiny new user in the database:

var company = _model.Companies.First();
company.Users.Add(new User(1, "John", "Smith"));
_model.SaveChanges();

However, if I do this, then I get nothing new in the database, and no exceptions thrown:

var existingUser = _model.Users.First();
var company = existingUser.Company;
company.Users.Add(new User(1, "John", "Smith"));
_model.SaveChanges();

So it appears that if I add a User to the Company that is pulled directly from the model, then everything works fine. However if the User is added to a Company that is pulled as a navigation property of another object, then it doesn't work.

Can someone tell me if this is expected behaviour, or if there is something I can do to make it so that it is?

Thanks!

Edit

To clarify what I mean by "it doesn't work";

  • Stepping through the code shows the execution pointer going past all lines without throwing an exception.
  • No new row is added to the database
  • If I check company.Users in quick watch, the new user has indeed been added to the company - it's just not being saved to the database.

I've done a little more playing, and it seems that if I do this, I get an exception:

var existingUser = _model.Users.First();
var company = existingUser.Company;
_model.ObjectStateManager.GetObjectStateEntry(company);

The exception is:

System.InvalidOperationException: The ObjectStateManager does not contain an ObjectStateEntry with a reference to an object of type 'ABC.DEF.Company'.

Doing that for the first (working) scenario provides me with an ObjectStateEntry back without throwing an exception.

A: 

In EF2 there was deferred loading of entities. I don't know if Microsoft changed this in EF4. That means existingUser.Company is null after loading existingUser. There are several solutions:


var existingUser = _model.Users.Include("Company").First();
var company = existingUser.Company;
...

or


var existingUser = _model.Users.First();
existingUser.CompanyReference.Load();
var company = existingUser.Company;
...

Please consider that these possibilities are some ways I know from the old EF.

But if found this as proper solution for EF4. I think you want to enable the lazy loading of the related entities.

Regards.

DHN
But he said that there was no exception. One should expect a NullReferenceException when accessing company.users if LazyLoading was disabled.
Slauma
Hmm "it doesn't work" could be anything. ;) As long as he doesn't give more details it's very difficuilt to provide some better advices.
DHN
I've tried to further clarify what I mean by 'not working', and I can confirm that Lazy Loading is enabled.
Robert
A: 

I figured it out...

I simplified the code for the purpose of this question, but when I drilled into it, I realised that the _model instance that I was getting the user from was different to the one that was saving the company. So really, what I was actually doing was something more like this:

var existingUser = _modelFromUserDAL.Users.First();
var company = existingUser.Company;
company.Users.Add(new User(1, "John", "Smith"));
_modelFromCompanyDAL.SaveChanges();
Robert