这是类似问题的链接:
我想知道具体原因是什么,上面链接给的答案看得个大概,不是很明白。
为什么新添加的元素,然后进行查询,结果就无法只使用延迟加载呢,无法生成动态代理对象呢?而查询已经存在的元素则可以使用延迟加载,并且能够正确生成动态代码对象?
麻烦熟悉的园友再给解释解释^_^
问题代码截图:
public class OrgChart { [Key] [DatabaseGenerated(DatabaseGeneratedOption.None)] public int Id { get; set; } public string Name { get; set; } public virtual IList<OrgNode> Nodes { get; set; } } public class OrgNode { [Key] [DatabaseGenerated(DatabaseGeneratedOption.None)] public int Id { get; set; } public string Name { get; set; } public virtual OrgChart Chart { get; set; } public virtual IList<User> Users { get; set; } } public class User { [Key] [DatabaseGenerated(DatabaseGeneratedOption.None)] public int Id { get; set; } public string Name { get; set; } public virtual OrgNode Node { get; set; } }
你需要把 OrgNode 实例的创建委托给 DbContext 来执行,这样它才能在 OrgNode 构造时注入额外的代理逻辑,从而实现 延迟加载(可以同 IoC 、AOP概念做个比较,也可以使用下 Unity。这么看来,EF 采用了构造注入,而没实现属性注入 )。
Hi Launcher,
那这样的话我们平时的用法: /// <summary> /// Add entity /// </summary> /// <param name="entity">New entity</param> public virtual void Add(T entity) { this.Context.Set<T>().Add(entity); this.Context.SaveChanges(); } 这样不是有问题?按照你的解释,我们是不是应该这样: OrgNode node = db.Set<OrgNode>().Create(); node.xx = xxx.
//然后再调用Add方法 Add(node);
@kaleyroy: 对,通过 EF 来创建实体。
@Launcher:
按照你的步骤,也是OK的。
不过我有些疑问,比如我用Repository模式,不想暴露DbContext在外部使用。
我只能再在内部拼装我的实体? 还有其他的方式吗?
@kaleyroy: Repository 应该提供 Create 方法,我记得 DDD 中仓储模式是建议给对象的创建提供工厂方法的。 也就是说你的代码中不应该存在 new 对象的语句,而统一使用 Repository 的 Create 方法在仓储中创建一个新的对象,这也比较符合 DDD 的语义。
@Launcher:
明白,谢谢^_^
新添加的属性增加virtual了吗?
哈哈。。。 谢谢dudu.
是加了,这个我忘贴上去了,我补充下剩下的内容。
@kaleyroy: 还是没看明白,究竟是哪个新添加的元素无法延迟加载?
@dudu:
你看到这张截图里面 newNode的类型是 OrgNode,这个OrgNode里面的属性比如Users是不具有延迟加载功能的。
而这张截图里面的existsNode类型是DynamicProxies.OrgNode_34.... 动态代理类型,这种类型才具有延迟加载功能。
@kaleyroy:
试试将newNode的代码放到单独的ExampleDbContext中查询
@dudu:
嗯,这样是可以的。不过好像我们的场景一般都局部共享一个DbContext.
@kaleyroy: 对于这样的场景,EF认为没有必要生成代理类,我也这么认为
@dudu:
明白,谢谢dudu!