我猜这是不可能的,但无论如何我会把它扔出去。在CTP4中使用EF4 CodeFirst API进行编程时是否可以使用CreateSourceQuery?我想热切地加载附加到属性集合的属性,如下所示:
var sourceQuery = this.CurrentInvoice.PropertyInvoices.CreateSourceQuery();
sourceQuery.Include("Property").ToList();
但是当然CreateSourceQuery是在EntityCollection<T>
上定义的,而CodeFirst是使用普通的ICollection
(显然)。有没有办法转换?
我已经完成了以下工作,但这并不是我想要的。任何人都知道如何从下面的内容到上面的内容(下面的代码来自一个继承DbContext的类)?
ObjectSet<Person> OSPeople = base.ObjectContext.CreateObjectSet<Person>();
OSPeople.Include(Pinner => Pinner.Books).ToList();
谢谢!
编辑:这是我的版本,由zeeshanhirani发布的解决方案 - 顺便说一下,这本书很棒!
dynamic result;
if (invoice.PropertyInvoices is EntityCollection<PropertyInvoice>)
result = (invoices.PropertyInvoices as EntityCollection<PropertyInvoice>).CreateSourceQuery().Yadda.Yadda.Yadda
else
//must be a unit test!
result = invoices.PropertyInvoices;
return result.ToList();
EDIT2:
好的,我刚刚意识到你在使用动态时无法调度扩展方法。所以我猜我们不像那样像Ruby一样充满活力,但上面的例子很容易修改以符合这个限制
EDIT3:
正如zeeshanhirani博客文章中所提到的,只有当(并且仅当)您拥有启用了更改的代理时,这才会生效,如果您的属性的所有被声明为虚拟,则会创建代理。这是使用带有POCO的CreateSourceQuery
的方法的另一个版本public class Person {
public virtual int ID { get; set; }
public virtual string FName { get; set; }
public virtual string LName { get; set; }
public virtual double Weight { get; set; }
public virtual ICollection<Book> Books { get; set; }
}
public class Book {
public virtual int ID { get; set; }
public virtual string Title { get; set; }
public virtual int Pages { get; set; }
public virtual int OwnerID { get; set; }
public virtual ICollection<Genre> Genres { get; set; }
public virtual Person Owner { get; set; }
}
public class Genre {
public virtual int ID { get; set; }
public virtual string Name { get; set; }
public virtual Genre ParentGenre { get; set; }
public virtual ICollection<Book> Books { get; set; }
}
public class BookContext : DbContext {
public void PrimeBooksCollectionToIncludeGenres(Person P) {
if (P.Books is EntityCollection<Book>)
(P.Books as EntityCollection<Book>).CreateSourceQuery().Include(b => b.Genres).ToList();
}
答案 0 :(得分:4)
可以向您派生的上下文添加一个方法,该方法为实体实例上的给定导航创建源查询。为此,您需要使用底层的ObjectContext,其中包含一个关系管理器,它为每个导航公开底层实体集合/引用:
public ObjectQuery<T> CreateNavigationSourceQuery<T>(object entity, string navigationProperty)
{
var ose = this.ObjectContext.ObjectStateManager.GetObjectStateEntry(entity);
var rm = this.ObjectContext.ObjectStateManager.GetRelationshipManager(entity);
var entityType = (EntityType)ose.EntitySet.ElementType;
var navigation = entityType.NavigationProperties[navigationProperty];
var relatedEnd = rm.GetRelatedEnd(navigation.RelationshipType.FullName, navigation.ToEndMember.Name);
return ((dynamic)relatedEnd).CreateSourceQuery();
}
你可以得到想象并接受导航属性的Func以避免必须指定T,但以下是如何使用上述函数:
using (var ctx = new ProductCatalog())
{
var food = ctx.Categories.Find("FOOD");
var foodsCount = ctx.CreateNavigationSourceQuery<Product>(food, "Products").Count();
}
希望这有帮助!
〜罗文
答案 1 :(得分:3)
绝对有可能这样做。如果您使用virtual
关键字标记了集合属性,那么在运行时,ICollection
的实际具体类型将是EntityCollection
,它支持CreateSourceQuery
以及随附的所有好东西默认代码生成器。我就是这样做的。
public class Invoice
{
public virtual ICollection PropertyInvoices{get;set}
}
dynamic invoice = this.Invoice;
dynamic invoice = invoice.PropertyInvoices.CreateSourceQuery().Include("Property");
我写了一篇关于类似内容的博文。请注意,依靠ICollection
的内部实现转换为EntityCollection
并不是一种好习惯。
以下是您可能会发现有用的博客文章