【问题标题】:Using CreateSourceQuery in CTP4 Code First首先在 CTP4 代码中使用 CreateSourceQuery
【发布时间】:2010-08-03 16:10:09
【问题描述】:

我猜这是不可能的,但无论如何我都会把它扔掉。在 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 的博客文章中提到的,这仅在(且仅当)您具有启用更改的代理时才有效,如果您的所有属性都被声明为虚拟,则会创建该代理。这是将 CreateSourceQuery 与 POCO 结合使用的方法的另一个版本

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();
    }

【问题讨论】:

  • 查看实际类型(实现ICollection)。你可以投吗?
  • 是的,克雷格,你一直都做对了。

标签: entity-framework-4


【解决方案1】:

可以向派生上下文添加一个方法,该方法为实体实例上的给定导航创建源查询。为此,您需要使用底层 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();
}

希望这会有所帮助!

~罗文

【讨论】:

    【解决方案2】:

    这绝对是可能的。如果你用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 并不是一个好习惯。 以下是您可能会觉得有用的博文

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

    【讨论】:

    • 啊哈——天才!我会这样做(在 DAO 方法内部,或者在您构建查询的任何地方)动态结果; if (invoice.PropertyInvoices is EntityCollection) result = (invoices.PropertyInvoices as EntityCollection).CreateSourceQuery().Yadda.Yadda.Yadda else //必须是单元测试!结果 = invoices.PropertyInvoices;返回结果.ToList();
    • 呸——让我重写它作为答案以获得更好的格式。嘿,另一方面,我喜欢你的书。我刚刚完成它 - 太棒了!干得好。
    • 谢谢。现在你欠我一个亚马逊评论。除了 Apress 赚钱之外,这并不是说它可以帮助我在书中赚钱,它只会帮助我们编写本书的第二版。
    • 我已经这样做了 :) 再添加 2 条 5 星评论以获得平均 5 星。也许我只是对以前的 Apress EF4 书有多糟糕(“Pro”我的 a$$!)感到愤怒,但我真的很喜欢你的书。正如评论所说,您可能会考虑将一些常见的设置步骤复制粘贴到一个位置以保存页面,但是嘿,如果您这样做了,其他读者会抱怨不断翻转!
    猜你喜欢
    • 1970-01-01
    • 2018-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-03
    • 2020-01-19
    • 2016-06-06
    相关资源
    最近更新 更多