What would cause the Entity Framework to save an unloaded (but lazy loadable) reference over existing data? -


i'm running interesting bug in asp.net mvc 3 application using entity framework 4.1 code first. have 3 classes/tables joined in sequence. there's invitation has reference project has reference company.

when load company , save fine. same projects. when invitation gets edited , saved, wipes out fields in company. they're blank!

when edit project, need show info company, i'm explicitly loading .include(x => x.company). when edit invitation though, don't need company haven't bothered including it.

i'd think if object wasn't ever loaded, there shouldn't reason ef flag edited, right?

update: after debugging via commenting out lines of code i've narrowed down some.

the actual object being cleared contact object that's referenced company. , wasn't being cleared new contact created in constructor (so wouldn't null new companies.)

so guess changes question: is there way have referenced property set default value without breaking ef?

public class invitationcontroller {     [httppost]     public redirecttorouteresult acceptinvitation(int id, int companyid, int projectid, invitation invitation)     {         // line triggered problem loading company, without          // eagerly loading contacts.         checkauthorizationedit(companyid, communicationservice.getbyid(id));          var dbresponse = invitationservice.getpreviousresponse(companyid, projectid);         dbresponse.willbid = invitation.willbid;         invitationservice.save(dbresponse);          return redirecttoaction("response", new { id, companyid } );     }      private void checkauthorizationedit(int companyid, communication communication)     {         var companyids = communication.distributionlist.companies.select(c => c.id).tolist();         //checkauthorization(companyids);     } }  public class invitationservice {     public invitation getpreviousresponse(int companyid, int projectid)     {         return (from invitation in _db.invitations                 invitation.projectid == projectid && invitation.sendercompanyid == companyid                 select invitation).singleordefault();     }      public void save(invitation invitation)     {         _db.savechanges();     } }  public class invitation {     public int id { get; set; }     public int projectid { get; set; }     [foreignkey("projectid")]     public virtual project project { get; set; }     // ... }   public class project {     public int id { get; set; }     public int companyid { get; set; }     [foreignkey("companyid")]     public virtual company company { get; set; }     // ... }  public class company {     public company()     {         maincontact = new contact();     }      public int id { get; set; }     public virtual contact maincontact { get; set; }     // ... }  public class contact {     public int id { get; set; }     public string addressline1 { get; set; }     // ... } 

if understand right have this:

public class company {     public company()     {         maincontact = new contact();     }      public int id { get; set; }     public virtual contact maincontact { get; set; } } 

a simple code this...

var company = context.companies.find(1); context.savechanges(); 

...will indeed create new empty contact in database.

the main conclusion draw is: don't instantiate reference navigation properties in constructor! (instantiating navigation collections ok, think, long leave content empty. instantiating properties of complex types in constructor fine because not other entities.)

if want make sure create new contact new company, perhaps static factory method in company class better option:

public static company createnewcompany() {     return new company { maincontact = new contact() }; } 

this work:

var company = context.companies.find(1); context.entry(company.maincontact).state = entitystate.detached; context.savechanges(); 

but such procedure looks ridiculous.

edit:

it's way automatic change detection causes behaviour. code...

context.configuration.autodetectchangesenabled = false; var company = context.companies.find(1); context.savechanges(); 

...doesn't create new contact. it's change detection working internally in savechanges find thinks identify maincontact in company new entity , puts added state context.


Comments

Popular posts from this blog

linux - Using a Cron Job to check if my mod_wsgi / apache server is running and restart -

actionscript 3 - TweenLite does not work with object -

jQuery Ajax Render Fragments OR Whole Page -