Spoof loading doesn't work

I am migrating my project from EF 4.0 to EF 6.0. I am trying to get properties from a nav entity after inserting a new entity. This code works without issue in EF 4.0, but when I try to run in EF 6.0, I get a NullReference Exception.

User:

public partial class users
{
    public int RID { get; set; }
    public string Name { get; set; }
    public Nullable<int> LangRef { get; set; }

    public virtual language language { get; set; }
}

      

Tongue:

public partial class language
{
    public language()
    {
        this.users = new HashSet<users>();
    }

    public int RID { get; set; }
    public string Name { get; set; }

    public virtual ICollection<users> users { get; set; }
}

      

Test code:

test1Entities testEnt = new test1Entities();
users user = new users();
user.Name = "asd";
user.LangRef = 1;//That ID refer to English record in Language entity
testEnt.users.Add(user);
testEnt.SaveChanges();

string lang = user.language.Name;//Should return "English". However language property seem null

      

Model:

Model:

+3


source to share


2 answers


new users()

Try instead testEnt.users.Create()

. The difference is that the returned object will be a proxy class, which is required to lazily load navigation properties.

As an aisde, doing the opposite and setting the navigation property language

and not the foreign key value LangRef

should actually set the LangRef property correctly when called SaveChanges()

.



See DbSet.Create Method on MSDN.

0


source


You say you user.language.Name

should return English, you don't install it anywhere. You must set the language when creating a new user.

test1Entities testEnt = new test1Entities();
users user = new users();
user.Name = "asd";
user.LangRef = 1;

// grab the english language entity from the database
language englishLanguage = entities.First(o => o.Name == "English");

// set the users language to english
user.language = englishLanuage;

testEnt.users.Add(user);
testEnt.SaveChanges();

      

Imagine if you insert a user with raw SQL you would run something like this

INSERT INTO users (name, languageId) VALUES ('Foo', 1);

      

Where 1 is the RID entry in the language table that corresponds to the English language. 1 is a foreign key in the users table that maps the user to their language. Same as with raw SQL, you must explicitly tell the Entity Framework what language the user has. This is done by requesting the DbContext for the language (which returns a tracked object) and then setting that object to the navigation property.


Alternatively, if you know the primary key of the language record in advance, you can create a new language (with the correct RID) and attach it to the DbContext, then set it to the navigation property. This would make it so that there are one fewer database queries. While this would be a little more efficient, you should do whatever is simpler / makes the most sense to you. Get it working, then you can optimize bottlenecks later.

language englishLanguage = new language() { RID = 1, Name = "English" };
testEnt.languages.Attach(language);

user.language = englishLanguage;
testEnt.users.Add(user);

      




Edit

Given your recent changes, it is now clearer what you are trying to do. I didn't realize that LangRef was your foreign key as it was decimal and doesn't follow normal naming conventions.

The solution described in this answer fooobar.com/questions/142330 / ... . The problem comes from Entity Framework caching. After SaveChanges()

(to update the RID), you can detach and re-pull the user to update it.

testEnt.users.Add(user);
testEnt.SaveChanges();
((IObjectContextAdapter)testEnt).ObjectContext.Detach(user);
users user = testEnt.First(o => o.RID == user.RID);
Console.WriteLine(user.language.Name);

      

Opening a new DbContext also works, but it brings up another connection to the database.

As described in the above answer, testEnt.Entry<users>(user).Reload()

unfortunately not working.

+2


source







All Articles