2014-01-20 60 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構建以查詢實體

我也曾嘗試以下方法,但它要求退貨IEnumerable<int>

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

我的問題是如何創建我的實體類在LINQ實體的新實例,所以不是每個屬性都被填充。

+1

你可以顯示'dbSet'變量的定義嗎?並且您能擴展「在返回類型中有麻煩」嗎? – Colin

回答

1

您無法傳遞創建AdminMenu實例的選擇器,因爲它是在您的實體框架上下文中映射的類型。所以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); 

答案比我想象的要長,但我希望它有幫助!