2016-02-12 1 views
1

Недавно я начал работать с EF и MVC в .Net Web Applications, и у меня возникла проблема, и мне хотелось узнать, что вы думаете и вы могли бы указать мне в правильном направлении.Использование ICollection с Entity Framework от одного до многих и как повысить производительность

Итак, у меня есть два класса: DataGroup и DataElements. Элемент DataElement может находиться в одной DataGroup или none. Я использовал свободно API в DataContext для достижения этой цели:

modelBuilder.Entity<DataGroup>() 
      .HasMany(dg => dg.DataElements) 
      .WithOptional() 
      .HasForeignKey(de => de.DataGroup_Id); 

В моем классе DataGroup я получил следующее:

public virtual ICollection<DataElement> DataElements { get; set; } 

    [NotMapped] 
    public ICollection<DataElement> RecentDataElements //returns the last 15 data elements 
    { 
     get 
     { 
      return DataElements.OrderByDescending(de => de.GeneratedDateTime).Take(15).Reverse().ToList(); 
     } 
    } 

    [NotMapped] 
    public DataElement LatestDataElement //returns the latest data element (if any) 
    { 
     return DataElements.OrderByDescending(de => de.GeneratedDateTime).FirstOrDefault(); 
    } 

Так что вопрос, я с кодом выше, что, когда Я называю LastDataElement или RecentDataElements, я в конечном итоге жду немного.

Я считаю, что это связано с тем, что свойство DataElements в классе DataGroup является ICollection и RecentDataElements и LastDataElement, что приводит к тому, что EF загружает все элементы данных в память перед сортировкой и возвратом подмножества (могут быть тысячи DataElements в DataGroup).

Есть ли способ сделать это более эффективным?

Я играл с идеей прямого запроса к datacontext, а не с использованием свойства DataElements, но я хотел посмотреть, есть ли какие-либо другие варианты, которые я должен рассмотреть. Мне сказали коллеги, что было бы плохой практикой поместить datacontext в модель (независимо от того, правильны они или нет, это другая проблема).

Благодарим за помощь и совет. Очень ценится :)

ответ

1

Вкратце: No.

Как уже указывает атрибут NotMapped, это свойство linq-to-entity не знает ни о чем, и его невозможно заполнить путем фильтрации по базе данных. Что я буду делать в вашем месте удалить Notmapped свойства из модели все вместе и создать ViewModel:

public class DataGroupViewModel 
{ 
    public DataGroup DataGroup {get; set;} 

    public ICollection<DataGroup> RecentDataElements {get; set;} 
} 

И использовать проекцию в запросе, чтобы заполнить эту точку зрения:

var result = ctx.DataGroups.Where(...).Select(d => new DataGroupViewModel 
{ 
    DataGroup = d; 
    RecentDataElements = d.DataElements.OrderByDescending(de => de.GeneratedDateTime) 
     .FirstOrDefault(); 
} 

Это, конечно, заставляет вас создавать другую модель, но это самый чистый и быстрый способ сделать это. Также ваши коллеги правы, это - - плохой способ делать вызовы db в вашей модели, модель - это контейнер для данных, не более того, у него не должно быть логики внутри него для запроса базы данных.

Чтобы сделать это немного чище, вы можете написать некоторые методы расширения можно использовать повторно для получения модели:

Func<IQueryable<DataGroup>,IEnumerable<DataGroupViewModel>> GetDataGroupDTO = 
    d => d.Select(dt => new DataGroupViewModel 
    { 
     DataGroup = dt; 
     RecentDataElements = dt.DataElements.OrderByDescending(de => de.GeneratedDateTime) 
     .FirstOrDefault(); 
    } 

Затем вы можете написать запрос более чистый:

IEnumerable<DataGroupViewModel> result = ctx.DataGroups.Where(...).GetDataGroupDTO(); 
Смежные вопросы