实体框架延迟加载不起作用

时间:2014-08-17 22:37:46

标签: c# .net entity-framework entity-framework-6

我正在将我的项目从EF 4.0迁移到EF 6.0。 我试图在插入新实体后从导航实体获取属性。该代码在EF 4.0中没有任何问题,但是当我尝试在EF 6.0中运行时,我得到了NullReference异常。

用户实体:

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; }
}

语言实体:

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; }
}

测试代码:

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:

2 个答案:

答案 0 :(得分:2)

你说user.language.Name应该返回英文,你没有在任何地方设置。您必须在创建新用户时设置语言。

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();

想象一下,如果您使用原始SQL插入用户,则可以运行类似这样的

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

其中1是语言表中映射到英语的记录的RID。 1是users表中的外键,用于将用户映射到他们的语言。与原始SQL相同,您必须明确告诉Entity Framework用户使用哪种语言。这是通过查询语言的DbContext(返回跟踪的实体),然后将该实体设置为导航属性来完成的。


或者,如果您事先知道语言记录的主键,则可以创建一个新的语言实体(使用正确的RID)并将其附加到DbContext,然后将其设置为导航属性。这样就可以减少对数据库的查询次数。虽然这会更有效,但你应该做更容易/最有意义的事情。让它工作,然后你可以在以后优化瓶颈。

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

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

修改

鉴于您最近的编辑,现在更清楚您要做什么。我没有意识到LangRef是你的外键,因为它是一个小数,并没有遵循正常的命名约定。

此答案中描述了解决方案https://stackoverflow.com/a/18251442/1160036。问题来自实体框架缓存。在SaveChanges()之后(以便更新RID),您可以分离并重新拉取用户以刷新它。

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);

打开一个新的DbContext也可以,但这确实会导致另一个与数据库的连接。

如上面的答案中所述,遗憾的是testEnt.Entry<users>(user).Reload()不起作用。

答案 1 :(得分:0)

而不是使用new users()尝试testEnt.users.Create()。不同之处在于返回的对象将是延迟加载导航属性所需的代理类。

作为aisde,执行相反的操作并设置language导航属性本身而不是LangRef外键值时,实际上应该在调用SaveChanges()时正确设置LangRef属性。

请参阅MSDN上的DbSet.Create method