首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >CreateSourceQuery在CTP4代码中的应用

CreateSourceQuery在CTP4代码中的应用
EN

Stack Overflow用户
提问于 2010-08-03 16:10:09
回答 2查看 2.1K关注 0票数 7

我猜这是不可能的,但我还是会把它扔出去的。在使用EF4 EF4 CodeFirst API进行CTP4编程时,是否可以使用CTP4?我想急切地加载附加到属性集合中的属性,如下所示:

代码语言:javascript
复制
var sourceQuery = this.CurrentInvoice.PropertyInvoices.CreateSourceQuery();
sourceQuery.Include("Property").ToList();

当然,CreateSourceQuery是在EntityCollection<T>上定义的,而CodeFirst使用的是普通的旧ICollection (很明显)。有什么方法可以改变吗?

我得到了下面的工作,但这不是我想要的。任何人都知道如何从下面的代码到上面的代码(下面的代码来自继承DbContext的类)。

代码语言:javascript
复制
ObjectSet<Person> OSPeople = base.ObjectContext.CreateObjectSet<Person>();
OSPeople.Include(Pinner => Pinner.Books).ToList();

谢谢!

编辑:这是我的解决方案由zeeshanhirani发布的版本-顺便说一句,他的书太棒了!

代码语言:javascript
复制
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:

好的,我刚刚意识到您不能在使用dynamic时分派扩展方法。所以我想我们不像Ruby那么动态,但是上面的例子很容易被修改以适应这个限制。

EDIT3:

正如在zeeshanhirani的博客文章中提到的,只有当(并且只有)您拥有启用更改的代理时才能工作,如果您的所有属性都声明为虚拟的,则会创建这些代理。下面是该方法与POCOs一起使用CreateSourceQuery的另一个版本

代码语言:javascript
复制
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();
    }
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2010-08-05 02:01:26

这样做是完全有可能的。如果您用virtual关键字标记了集合属性,那么在运行时,ICollection的实际具体类型将是EntityCollection,它支持CreateSourceQuery和默认代码生成器附带的所有优点。我就是这样做的。

代码语言:javascript
复制
public class Invoice
{
    public virtual ICollection PropertyInvoices{get;set}
}

dynamic invoice = this.Invoice;
dynamic invoice = invoice.PropertyInvoices.CreateSourceQuery().Include("Property");

我写了一篇类似的博客文章。请注意,依赖于将ICollection转换为EntityCollection的内部实现并不是一个好的实践。下面是你可能觉得有用的博客文章

http://weblogs.asp.net/zeeshanhirani/archive/2010/03/24/registering-with-associationchanged-event-on-poco-with-change-tracking-proxy.aspx

票数 3
EN

Stack Overflow用户

发布于 2010-08-10 23:01:22

可以向派生上下文中添加方法,为实体实例上的给定导航创建源查询。要做到这一点,您需要使用基础ObjectContext,它包括一个关系管理器,它公开了每个导航的底层实体集合/引用:

代码语言:javascript
复制
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,但是下面是如何使用上面的函数:

代码语言:javascript
复制
using (var ctx = new ProductCatalog())
{
    var food = ctx.Categories.Find("FOOD");
    var foodsCount = ctx.CreateNavigationSourceQuery<Product>(food, "Products").Count();
}

希望这能有所帮助!

罗文

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3398445

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档