我在从EF 4.3 Code First数据库加载实体时遇到问题。 我已将代码简化为此工作示例代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity.Infrastructure;
namespace CodeFirst {
class Program {
static void Main(string[] args) {
Database.SetInitializer(new DropCreateDatabaseAlways<Context>());
Database.DefaultConnectionFactory = new SqlCeConnectionFactory("System.Data.SqlServerCe.4.0");
using (Context context = new Context()) {
A a = new A { B = new B { Foo = 1 } };
context.As.Add(a);
context.SaveChanges();
Print(context); // B has ID=1, Foo=1
}
using (Context context = new Context()) {
Print(context); // B is null
}
Console.ReadLine();
}
public static void Print(Context context) {
A a = context.As.Single();
Console.WriteLine("A: ID=" + a.Id);
if (a.B == null) {
Console.WriteLine("B: null");
}
else {
Console.WriteLine("B: ID=" + a.B.Id + ", Foo=" + a.B.Foo);
}
}
}
class Context : DbContext {
public DbSet<A> As { get; set; }
}
class A {
public int Id { get; set; }
public B B { get; set; }
}
class B {
public int Id { get; set; }
public int Foo { get; set; }
}
}
输出结果为:
A: ID=1
B: ID=1, Foo=1
A: ID=1
B: null
在此示例代码中,出于某种原因,当我在新A
中检索Context
时,其子属性B
为null
。如果我设置断点并在B
为null
的位置连接到数据库,则所有内容都按顺序排列:
Table: A
--------
Id B_Id
1 1
Table: B
--------
Id Foo
1 1
我只是想学习Code First,所以我可能会有一个严重的误解,但这对我来说似乎很奇怪。任何人都可以解释这种行为吗?
答案 0 :(得分:2)
到目前为止提供的两个答案都是不必要的麻烦。
只需将您的实体类设为公开,并将导航属性声明为virtual
,EF会懒惰地加载它们(即根据需要)
当您访问导航属性以使其工作时,DbContext
必须打开(即不处理)。
答案 1 :(得分:0)
您需要包含它们。
你需要做这样的事情:
var aWithNavProperties = As.Where(a=>a.Id==id).Include(a=>a.B).Single();
答案 2 :(得分:0)
默认情况下,当明确告知实体框架时,实体框架只会加入表格(这就是导航属性通常可以使用的连接)。您可以使用Include()
方法:
var a = context.As.Include("B").Single();
您还可以在加载实体本身后加载属性。这是Lazy Loading模式的一个实现(应该小心处理,它可以是一个真正的PITA)
var a = context.As.Single();
// some other code
if (!a.BReference.IsLoaded())
a.BReference.Load();