Сначала используйте CreateSourceQuery в CTP4-коде - PullRequest
7 голосов
/ 03 августа 2010

Полагаю, это невозможно, но я все равно его выброшу.Можно ли использовать 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:

Как упомянуто в блоге zeeshanhiranipost, это работает только в том случае, если (и только если) у вас есть прокси с поддержкой изменений, которые будут созданы, если все ваших свойств объявлены виртуальными.Вот еще одна версия того, как метод может выглядеть для использования CreateSourceQuery с POCOs

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 ]

4 голосов
/ 11 августа 2010

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

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

~ Роуэн

3 голосов
/ 05 августа 2010

Определенно это возможно.Если вы пометили свойство коллекции ключевым словом 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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...