Pau*_*ugt 6 c# linq linq-to-entities entity-framework
我正在寻找一种从iQueryable对象动态创建选择列表的方法.
具体的例子,我想做类似以下的事情:
public void CreateSelectList(IQueryable(of EntityModel.Core.User entities), string[] columns)
{
foreach(var columnID in columns)
{
switch(columnID)
{
case "Type":
SelectList.add(e => e.UserType);
break;
case "Name":
SelectList.add(e => e.Name);
break;
etc....
}
}
var selectResult = (from u in entities select objSelectList);
}
Run Code Online (Sandbox Code Playgroud)
因此,所有属性都是已知的,但我事先并不知道要选择哪些属性.这将通过columns参数传递.
我知道我将遇到selectResult类型的问题,因为当选择列表是动态的时,编译器不知道匿名类型的属性需要是什么.
如果上述情况不可能:我需要它的场景如下:
我正在尝试创建一个可以实现的类来显示分页/过滤的数据列表.这些数据可以是任何东西(取决于实现).使用的linq是实体的linq.所以它们直接链接到sql数据.现在我只想选择我实际在列表中显示的实体的列.因此我希望select是动态的.我的实体可能有一百个属性,但如果列表中只显示了3个属性,我不想生成一个选择所有100列数据的查询,然后只使用其中的3个.如果有一种我没有想到的不同方法,我会接受各种想法
编辑:
关于约束的一些澄清:- 查询需要使用linq到实体(请参阅问题主题)
- 实体可能包含100列,因此选择所有列然后只读取我需要的列不是一个选项.
- 最终用户决定要显示哪些列,因此要选择的列在运行时确定
- 我需要创建一个SINGLE选择,有多个select语句意味着对数据库有多个查询,我不想要
Iva*_*oev 17
动态选择表达到编译时已知类型可以容易地生成使用Expression.MemberInit
方法与MemberBinding
使用所创建的小号Expression.Bind
方法.
这是一个自定义扩展方法,它执行以下操作:
public static class QueryableExtensions
{
public static IQueryable<TResult> Select<TResult>(this IQueryable source, string[] columns)
{
var sourceType = source.ElementType;
var resultType = typeof(TResult);
var parameter = Expression.Parameter(sourceType, "e");
var bindings = columns.Select(column => Expression.Bind(
resultType.GetProperty(column), Expression.PropertyOrField(parameter, column)));
var body = Expression.MemberInit(Expression.New(resultType), bindings);
var selector = Expression.Lambda(body, parameter);
return source.Provider.CreateQuery<TResult>(
Expression.Call(typeof(Queryable), "Select", new Type[] { sourceType, resultType },
source.Expression, Expression.Quote(selector)));
}
}
Run Code Online (Sandbox Code Playgroud)
唯一的问题是什么是TResult
类型.在EF Core中,您可以传递实体类型(如EntityModel.Core.User
您的示例中所示),它将起作用.在EF 6及更早版本中,您需要一个单独的非实体类型,否则您将获得NotSupportedException
- 无法在LINQ to Entities查询中构造实体或复杂类型.
更新:如果你想要删除字符串列,我建议你用以下类替换扩展方法:
public class SelectList<TSource>
{
private List<MemberInfo> members = new List<MemberInfo>();
public SelectList<TSource> Add<TValue>(Expression<Func<TSource, TValue>> selector)
{
var member = ((MemberExpression)selector.Body).Member;
members.Add(member);
return this;
}
public IQueryable<TResult> Select<TResult>(IQueryable<TSource> source)
{
var sourceType = typeof(TSource);
var resultType = typeof(TResult);
var parameter = Expression.Parameter(sourceType, "e");
var bindings = members.Select(member => Expression.Bind(
resultType.GetProperty(member.Name), Expression.MakeMemberAccess(parameter, member)));
var body = Expression.MemberInit(Expression.New(resultType), bindings);
var selector = Expression.Lambda<Func<TSource, TResult>>(body, parameter);
return source.Select(selector);
}
}
Run Code Online (Sandbox Code Playgroud)
样本用法:
var selectList = new SelectList<EntityModel.Core.User>();
selectList.Add(e => e.UserType);
selectList.Add(e => e.Name);
var selectResult = selectList.Select<UserDto>(entities);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
5542 次 |
最近记录: |