我正在将我的项目从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
型号:
答案 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。