当我尝试使用某些返回类型时,我的存储库方法中的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
});
抛出异常:
无法在LINQ to Entities查询中构建AdminMenu
我也尝试过以下方法,但需要返回IEnumerable<int>
:
IEnumerable<AdminMenu> menus = workunit.Menu.List(x => x.Online == true,
selector: z => z.MenuID);
我的问题是如何在linq中为实体创建实体类的新实例,因此不会填充每个属性。
答案 0 :(得分:2)
您无法传递创建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);
答案比我想象的要长,但我希望它有所帮助!