Я предполагаю, что это невозможно, но я брошу его там так или иначе. Действительно ли возможно использовать 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 с 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();
}
Это определенно возможно сделать. Если вы обозначили свойство коллекции ключевым словом 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();
}
Надеюсь, это поможет!
~ Роуэн