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