Сначала используйте CreateSourceQuery в CTP4-коде

Я предполагаю, что это невозможно, но я все равно брошу это туда. Можно ли использовать CreateSourceQuery при программировании с EF4 CodeFirst API, в CTP4? Я хотел бы загрузить свойства, прикрепленные к коллекции свойств, например:

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

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

Можно добавить метод к производному контексту, который создает исходный запрос для данной навигации по экземпляру объекта. Для этого вам необходимо использовать базовый 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();
}

Надеюсь это поможет!

~ Rowan

Другие вопросы по тегам