2014-01-20 2 views
2

У меня возникла проблема с методом Select в моем методе репозитория, когда я пытаюсь использовать определенные типы возвращаемых данных.с использованием селектора в репозиториях структуры сущности

Метод вместилище, где я имею вопрос является:

public IEnumerable<T> List(Expression<Func<T, bool>> filter = null, 
      string include = "", 
      int Taked = 0, Expression<Func<T, T>> selector = null) 
{ 
    IQueryable<T> query = dbSet; 
    if (filter != null) 
     query = query.Where(filter); 

    #region Stringleri İnclude Eder 
    foreach (var includeProperty in 
     include.Split(new char[] {','}, 
         StringSplitOptions.RemoveEmptyEntries)) 
    { 
     query = query.Include(includeProperty); 
    } 
    #endregion 

    if (selector != null) 
     query = query.Select(selector); 
    if (Taked != 0) 
     return query.Take(Taked).ToList(); 
    return query.ToList(); 
} 

internal DbContext context; 
internal DbSet<T> dbSet; 

Я хочу вернуть мой класс сущностей с помощью метода выше, но я хочу только некоторые свойства должны быть заполнены. Я попробовал следующий подход:

AdminWork workunit = new AdminWork(); 
IEnumerable<AdminMenu> adminMenus = workunit.Menu.List(x => x.Online == true, 
    selector: z => new AdminMenu 
    { 
     MenuID = z.MenuID, 
     Name = z.Name, 
     Path = z.Path 
    }); 

Который бросает исключение:

AdminMenu не может быть построена в LINQ к Entities запрос

Я также попытался следующий подход, но это требуется вернуть IEnumerable<int>:

IEnumerable<AdminMenu> menus = workunit.Menu.List(x => x.Online == true, 
    selector: z => z.MenuID); 

Мой вопрос в том, как я могу создать новые экземпляры моего класса объектов в linq для объектов, поэтому не каждое свойство заполняется.

+1

Можете ли вы показать определение переменной 'dbSet'? И можете ли вы расширить «проблемы с возвратом»? – Colin

ответ

1

Вы не можете передать селектор, который создает экземпляры AdminMenu, потому что это тип, отображаемый в вашем контексте Entity Framework. Таким образом, Entity Framework хочет быть единственным, кто создает экземпляры этого типа, чтобы отслеживать изменения, возвращать один и тот же экземпляр, если он уже загружен и т. Д. См. this question для получения дополнительной информации.

Итак, если вы хотите вернуть список AdminMenu, вам не нужно будет передавать селектор (так как dbSet, который вы начинаете запрашивать, уже относится к этому типу). Вам нужно будет только передать селектор, если тип возврата отличается от типа в dbSet.

Вы могли бы иметь этот метод:. (Я сделал selector не-необязательный параметр, как он будет использоваться для определения TResult типа Я также предполагая T является общим параметром, определенным в классе, как public class Repository<T>, так что единственный общий параметр для добавления в методе TResult)

public IEnumerable<TResult> ListProjected<TResult>(Expression<Func<T, TResult>> selector, 
             Expression<Func<T, bool>> filter = null, 
             string include = "", 
             int Taked = 0) 
{ 
    IQueryable<T> query = dbSet; 
    if (filter != null) 
     query = query.Where(filter); 
    #region Stringleri İnclude Eder 

    foreach (var includeProperty in include.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) 
    { 
     query = query.Include(includeProperty); 
    } 

    #endregion 

    if (Taked != 0) 
     query = query.Take(Taked); 

    return query.Select(selector).ToList(); 
} 

И другая один, когда вы не хотите, чтобы проецировать в другой тип:

public IEnumerable<T> List(Expression<Func<T, bool>> filter = null, 
         string include = "", 
         int Taked = 0) 
{ 
    return ListProjected(x => x, filter, include, Taked); 
} 

Вы можете использовать эти методы, как в:

IEnumerable<AdminMenu> menus = workunit.Menu.List(x => x.Online == true); 

IEnumerable<int> menuIds = workunit.Menu.ListProjected(x => x.MenuID, 
                 x => x.Online == true); 

Наконец, если вы хотите только некоторые столбцы, вам нужно будет либо использовать анонимный объект или создать другой класс (например, в DTO), который содержит только столбцы заинтересованы в:

var menuSomeColumnsWithAnonymousObject = workunit.Menu.ListProjected(x => new 
{ 
    MenuID = x.MenuID, 
    Path = x.Path, 
    Name = x.Name 
}, x => x.Id == 1); 

var menuSomeColumnsWithDTO = workunit.Menu.ListProjected(x => new AdminMenuDTO 
{ 
    MenuID = x.MenuID, 
    Path = x.Path, 
    Name = x.Name 
}, x => x.Id == 1); 

Более длинный ответ, чем я думал, но я надеюсь, что это поможет!

Смежные вопросы