2013-10-16 63 views
2

我遇到了第一次检查似乎是在实体框架5实体框架5:实体是懒加载,但观察本地收集

我有一个T4产生的DbContext的错误当导航属性为null和实体类。请注意,我已经修改了默认的T4模板,以支持可观察的集合。

延迟加载启动,并在整个应用程序工作正常,当我这样做,除了:

courseEnrolment.Student.CourseEnrolments.ToList() 

也就是说,因为我已经在内存中加载的courseEnrolment,我访问它的父(Student),并加载与之关联的所有CourseEnrolments,其中还包括原始课程注册。发生这种情况时,第二个CourseEnrolment成功延迟加载到conext(和Local集合),但它的所有导航属性均为null,而不是相应的DynamicProxy

这就是新加载的CourseEnrolment的样子。需要注意的是所有的导航属性都为空,尽管被成功地从数据库中加载的正常属性:

enter image description here

这是一个正常的CourseEnrolment的样子:

enter image description here

没有任何一个有什么想法,为什么一个实体懒惰加载成功,然后无法通过延迟加载履行自己的导航属性?


更多的信息有关问题的

我已经成功地重新创建具有以下最低代码问题的源进行更新。这个问题似乎与我观察Local收藏有关。

 var context = new PlannerEntities(); 

     Debug.Assert(context.CourseEnrolments.Local.Count() == 0); 

     context.CourseEnrolments.Local.CollectionChanged += (sender, e) => 
     { 
      Debug.Assert(e.NewItems.OfType<CourseEnrolment>().All(x => x.Adviser != null), "newly added entity has null navigatigon properties"); 
     }; 

     var c1 = context.CourseEnrolments.Single(x => x.EnrolmentId == "GA13108937"); 

     Debug.Assert(context.CourseEnrolments.Local.Count() == 1); 
     Debug.Assert(context.CourseEnrolments.Local.All(x => x.Adviser != null)); 

     c1.Student.CourseEnrolments.ToList(); 

     Debug.Assert(context.CourseEnrolments.Local.Count() == 2); 

     Debug.Assert(context.CourseEnrolments.Local.All(x => x.Adviser != null),"some navigation properties were not lazy loaded"); 

CollectionChanged处理程序中的断言失败,其在这一点上的导航属性不满足指示。最终的断言不会失败,这将在事后处理ObservableCollection事件后指示实体完成。

任何想法如何访问Local集合的CollectionChanged事件的导航属性?

+0

您是否尝试过使用'Include'同时加载第二CourseEnrolments?例如'CourseEnrolments.Students.Include(“CourseEnrolments”)' – idipous

+0

您可以确认'Student.CourseEnrolments'是否标记为'virtual'? – Colin

+0

@idipous'Include'不是这些集合的方法,因为它们的类型为'ObservableCollection'。我唯一可以使用'Include'的地方就是上下文的DbSet,比如'entities.Students.Include('CourseEnrolment')。ToList();' – djskinner

回答

1

直到调用CollectionChanged事件之后才会创建延迟加载代理。使用分派器会导致将调用放置在消息队列中并在一段时间后执行(稍后多长时间不确定),因此在Debug.Assert被调用之前,CollectionChanged事件会执行并创建延迟加载代理。

但是,我强烈避免使用Dispatcher来达到这个目的,因为它是非确定性的并且存在竞争条件的风险。

为了像使用原始代码一样使用CollectionChanged事件,您需要更改跟踪代理,而不仅仅是延迟加载代理。对于Entity Framework生成更改跟踪代理,所有属性,无论是集合,对象还是原始类型,都需要将设置为虚拟

相关的问题:https://github.com/brockallen/BrockAllen.MembershipReboot/issues/290

+0

感谢有关潜在问题的解释。现在已经有一段时间了,但我确实相信最终会按照您的建议顺利完成T4代码生成路线。 – djskinner

0

嗯,我已经成功地得到它的工作由调度断言呼叫

context.CourseEnrolments.Local.CollectionChanged += (sender, e) => 
{ 
    Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>{ 
     Debug.Assert(e.NewItems.OfType<CourseEnrolment>().All(x => x.Adviser != null), "newly added entity has null navigation properties"); 
    })); 
}; 

这是最好的解决办法?