1

我刚刚开始使用EF 4.1 Code First,并注意到默认情况下,引用(导航属性)不会通过您使用LINQ-to-Entity查询的POCO实体加载到内存中。使用DbEntityEntry.Reference加载引用的实体,我没有取得任何成功。当我打电话给DbReferenceEntry.Load时,抛出以下异常:EF 4.1代码优先:如何将实体引用加载到内存中?

“已经有一个与此命令关联的打开DataReader,必须先关闭它。”

当我处于几个LINQ查询中时,关闭DataReader并不是我真正想做的事情。

例如,以下将不起作用:

using (db1 = new NorthindDbContext(new SqlConnection(this.NORTHWIND))) { 
orders = db1.Orders.Where(o => !(o.CustomerId == null || o.ShipperId == null || o.EmployeeID == null)); 
      foreach (var o in orders) { 
       Shipper s = o.Shipper;//exception: "There is already an open DataReader associated with this Command which must be closed first." 
       DbEntityEntry<Order> entry = db1.Entry(o); 
       DbReferenceEntry<Order, Shipper> shipper_reference = entry.Reference<Shipper>("Shipper"); 
       if (!shipper_reference.IsLoaded) { 
        shipper_reference.Load();     
       } 
      } 
     } 

下面是Order类:

public partial class Order 
{ 
    public System.Int32 ID { get; set; }     
    public System.Nullable<System.DateTime> OrderDate { get; set; } 
    public System.Nullable<System.DateTime> RequiredDate { get; set; } 
    public System.Nullable<System.DateTime> ShippedDate { get; set; }  
    public System.Nullable<System.Decimal> Freight { get; set; }   
    public Employee Employee { get; set; } 
    public Int32 CustomerId { get; set; } 
    public Customer Customer { get; set; } 
    public Int32 EmployeeID { get; set; } 
    /// <summary> 
    /// marked virtual for lazy loading 
    /// </summary> 
    public virtual Shipper Shipper { get; set; } 
    public Int32 ShipperId { get; set; } 
} 

我已经试过这标志着Order.Shipper属性作为虚拟的,我仍然得到同样的例外,如果当我运行的代码。

ObjectQuery.Include方法,确实工作:

[TestMethod]  
//configure MARS here? 
//Order.Shipper is not marked virtual now 
//... 
      using (db = new NorthindDbContext(new SqlConnection(this.NORTHWIND))) {       
      db.Orders.Include(o => o.Shipper) 
.Where(o => !(o.CustomerId == null || o.ShipperId == null || o.EmployeeID == null)); 
      foreach (var o in orders) { 
       Shipper s = o.Shipper;//null 
       DbEntityEntry<Order> entry = db.Entry(o); 
       DbReferenceEntry<Order, Shipper> shipper_reference = entry.Reference<Shipper>("Shipper"); 
       if (!shipper_reference.IsLoaded) { 
        shipper_reference.Load();//"There is already an open DataReader associated with this Command which must be closed first." 
       } 


      } 

随着EF 4.1代码首先,你如何让一个引用的实体加载到内存?

回答

3

如果您需要多个数据库读取工作在同一时间您必须allow MARS on your connection string但您真正的问题是在别处。

默认情况下,EF不加载导航属性。您必须使用懒惰或急切加载。延迟加载需要实体的所有导航属性是虚拟:

public class Order 
{ 
    ... 

    public virtual Shipper Shipper { get; set; } 
} 

一旦延迟加载和代理的创建允许上下文(默认),你的财产将被自动当第一次由代码访问加载。此访问必须在用于加载订单的相同上下文的范围内发生(您仍然可以在此处通过打开的DataReader来解决错误)。

另一种方法是用Order通过使用预先加载直接加载Shipper

var query = context.Orders.Include(o => o.Shipper)... 
+0

我已标记托运人属性作为虚拟的,但我仍然得到同样的异常。这个问题已经更新以反映这一点。我会尝试使用Inlcude方法,看看是否有效。 –

+0

您的班级中还有'Customer'属性 - 为了支持延迟加载,所有导航属性必须为'virtual'。你也必须配置MARS在外部查询范围内使用延迟加载。 –

相关问题