RRR*_*RRR 5 c# linq lambda linq-to-entities expression
我正在寻求有关如何使用LINQ以类型安全方式实现此目的的帮助.
我需要在包含许多列的"性能"表上执行搜索.根据为搜索指定的条件,我需要选择列并对具有给定值的列执行搜索.
private static IQueryable<Investment> PerformanceSearch(IQueryable<Investment> investments, **??? searchColumn**, double minValue, double maxValue)
{
var entity = ExtendedEntities.Current;
investments = from inv in entity.Investments
join performance in entity.Performances on inv.InvestmentID equals perfromance.InvestmentID
where **performance.searchColumn** >= minValue && **performance.searchColumn** = maxValue
return investments;
}
Run Code Online (Sandbox Code Playgroud)
现在我正在寻求你的帮助:
如何以类型安全的方式将列"searchColumn"传递给此方法?我正在考虑创建一个字典对象,以适应某种方式来维护实体框架中的列名.但不知道如何实现这一目标.
如何使用传递的columnName和应用where子句来执行LINQ查询.
我不能使用If Else或Switch案例如下所示是可能的搜索列表...
/*
* Search Columns can be:
* "Return1Month", "Return2Months", "Return3Months", ... almost 10 more and
* "Risk1Month", "Risk2Months", "Risk3Months", ... almost 10 more and
* "TrackingError1Month", "TrackingError2Months", "TrackingError3Months", ... almost 10 more and
* 2 more similar set of columns ...
*/
Run Code Online (Sandbox Code Playgroud)
我花时间在Stackoverflow,微软和其他博客上,并考虑使用动态LINQ,但它不是类型安全的.它似乎可以使用表达式实现,但无法实现.
任何建议表示赞赏.
编辑 -
另一个要提及的项目 - 所有搜索列都出现在"性能"表中.
毫无疑问,LINQ 表达式是以强类型方式动态构建 LINQ 查询的最佳方式。您放弃动态 LINQ 库是绝对正确的!LINQ 表达式一开始很难掌握,但我向您保证,最终的回报是值得付出努力的。
下面是一个使用 LINQ 表达式来完成您想要的操作的示例。您会注意到它不包含任何字符串列名称、switch 语句、辅助类或枚举。您需要导入System.Linq.Expressions名称空间才能使其工作:
编辑:该示例现在包括按一个连接表上的列进行过滤,同时从另一个表中选择一个元素。我还investments从方法中删除了参数,因为您实际上不需要传递该参数。您只需直接在方法中访问 EF 表(我将其替换为_performance和_investments)。
public static IQueryable<Investment> PerformanceSearch(Expression<Func<Performance, double>> searchColumn, double minValue, double maxValue) {
// LINQ Expression that represents the column passed in searchColumn
// x.Return1Month
MemberExpression columnExpression = searchColumn.Body as MemberExpression;
// LINQ Expression to represent the parameter of the lambda you pass in
// x
ParameterExpression parameterExpression = (ParameterExpression)columnExpression.Expression;
// Expressions to represent min and max values
Expression minValueExpression = Expression.Constant(minValue);
Expression maxValueExpression = Expression.Constant(maxValue);
// Expressions to represent the boolean operators
// x.Return1Month >= minValue
Expression minComparisonExpression = Expression.GreaterThanOrEqual(columnExpression, minValueExpression);
// x.Return1Month <= maxValue
Expression maxComparisonExpression = Expression.LessThanOrEqual(columnExpression, maxValueExpression);
// (x.Return1Month >= minValue) && (x.Return1Month <= maxValue)
Expression filterExpression = Expression.AndAlso(minComparisonExpression, maxComparisonExpression);
// x => (x.Return1Month >= minValue) && (x.Return1Month <= maxValue)
Expression<Func<Performance, bool>> filterLambdaExpression = Expression.Lambda<Func<Performance, bool>>(filterExpression, parameterExpression);
// use the completed expression to filter your collection
// This requires that your collection is an IQueryable.
// I believe that EF tables are already IQueryable, so you can probably
// drop the .AsQueryable calls and it will still work fine.
var query = (from i in _investments
join p in _performance.AsQueryable().Where(filterLambdaExpression)
on i.InvestmentId equals p.InvestmentId
select i);
return query.AsQueryable();
}
Run Code Online (Sandbox Code Playgroud)
您可以PerformanceSearch这样调用,使用这个简单的控制台应用程序作为示例:
private static IList<Investment> _investments;
private static IList<Performance> _performance;
static void Main(string[] args) {
// Simulate your two Entity Framework tables
BuildMockDataset();
// Return1Month is on Performance, but I return IQueryable<Investment>;
var results = PerformanceSearch(x => x.Return1Month, 300, 1000);
}
Run Code Online (Sandbox Code Playgroud)
double此示例足够通用,允许您从Performanceas传递属性searchColumn,并将最小值和最大值指定为 as double。