atm im在我的应用程序中编写通用过滤器模块。 我在创建适当的Expression>时遇到问题。我一般的SQL查询看起来像这样:
SELECT distinct ROW_NUMBER
FROM dbo.VIEW_ITEM item
WHERE CODE ='MyName'
AND EXISTS (SELECT *
FROM dbo.VIEW_ITEM
WHERE ROW_NUMBER = item.ROW_NUMBER
AND CODE='MyName'
AND (COL_NUMBER=1 AND DISPLAY='UserName'))
AND EXISTS (SELECT *
FROM VIEW_ITEM
WHERE ROW_NUMBER = item.ROW_NUMBER
AND CODE='MyName'
AND (COL_NUMBER=3 and DISPLAY='2261'))
ORDER BY ROW_NUMBER
(我认为)这是获取我需要的所有记录的最佳方法。我不能使用联接选项,因为我正在检查与主要查询相同的表 AND EXISTS 。
所以我的linq看起来像:
dboMVI.Where(mvi => mvi.Code == "MyCode")
.Where(mvi => dboMVI.Where(innerMvi => innerMvi.RowNumber == mvi.RowNumber && innerMvi.Code == "MyCode" && innerMvi.ColNumber == 1 && innerMvi.Display == "UserName").Any())
.Where(mvi => dboMVI.Where(innerMvi => innerMvi.RowNumber == mvi.RowNumber && innerMvi.Code == "MyCode" && innerMvi.ColNumber == 3 && innerMvi.Display == "2261").Any())
.Select(mvi => mvi.RowNumber)
.OrderBy(rn => rn)
.Distinct();
那应该返回我所有通过筛选的行数。 我设法创建了Expression,但我确信有更好的方法可以使其更通用,并将其放入我无法将其传递给DbContext的过滤模块中。
Expression<Func<ViewItem, bool>> filter =mvi =>
dboMVI.Where(innerMvi => innerMvi.RowNumber == mvi.RowNumber
&& innerMvi.Code == "MyCode" && innerMvi.ColNumber == 3 &&
innerMvi.Display == "2261").Any()
对于第二个过滤器:
Expression<Func<ViewItem, bool>> filter =mvi =>
dboMVI.Where(innerMvi => innerMvi.RowNumber == mvi.RowNumber
&& innerMvi.Code == "MyCode" && innerMvi.ColNumber == 1 &&
innerMvi.Display == "UserName").Any()
我的问题是如何为该LINQ查询创建通用表达式树?
我在任何地方都找不到创建这种树的示例。 我在join语句中找到了传递参数的示例。 但是在我的情况下,im从当前行的主查询号传递过来,而在子查询中,它会检查此特定行是否满足任何条件。
编辑:经过一些评论后,我注意到我在将查询值从真实值重写为演示时确实犯了错误。抱歉,现在希望已定:) 一般来说,它的工作解决方案只是在寻找更好的方法。
EDIT2: 我的问题在这里:
im试图从LINQ SQL查询中生成可以被EF Core使用的查询。 在我的SQL中,使用AND EXISTS的方式是在正文中引用与主查询中相同的表。在子查询中,IM还使用主查询中的ROW_NUMBER。 我怎么了我不知道如何创建表达式func(负责我的子查询),因为我不知道如何将我正在检查的当前ROW_NUMBER传递给它。我知道如何使表达式树成为简单的例子。但是我的身体里有常数或弦。但是在这种情况下,我的const每次都会更改为不同的值,因此无法进行硬编码。
我设法解决了这个问题。首先必须简化linq查询。
dboMVI.Where(mvi => mvi.Code == "MyCode")
.Where(mvi => dboMVI.Any(innerMvi => innerMvi.RowNumber == mvi.RowNumber && innerMvi.Code == "MyCode" && innerMvi.ColNumber == 1 && innerMvi.Display == "UserName"))
.Where(mvi => dboMVI.Any(innerMvi => innerMvi.RowNumber == mvi.RowNumber && innerMvi.Code == "MyCode" && innerMvi.ColNumber == 3 && innerMvi.Display == "2261"))
.Select(mvi => mvi.RowNumber)
.OrderBy(rn => rn)
.Distinct()
不必为任何表达式中的元素创建表达式树:
IQueryable<MaterializedViewItem> MyDtoList = Enumerable.Empty<MaterializedViewItem>().AsQueryable();
var insideProperty = Expression.Parameter(typeof(MaterializedViewItem), "mviAny");
var baseProperty = Expression.Parameter(typeof(MaterializedViewItem), "mviBaseAny");
MemberExpression condition0Code = Expression.Property(baseProperty, "MvCode");
ConstantExpression condition0CodeValue = Expression.Constant("ARAPP");
var condition0 = Expression.Equal(condition0Code, condition0CodeValue);
var predicateFirstElement = Expression.Lambda<Func<T, bool>>(condition0, baseProperty);
MemberExpression conditionACode = Expression.Property(insideProperty, "MvCode");
ConstantExpression conditionACodeValue = Expression.Constant("MyCode");
var conditionA = Expression.Equal(conditionACode, conditionACodeValue);
MemberExpression conditionACol = Expression.Property(insideProperty, "ColNumber");
ConstantExpression conditionAColValue = Expression.Constant((byte)1);
var conditionB = Expression.Equal(conditionACol, conditionAColValue);
MemberExpression conditionDisplay = Expression.Property(insideProperty, "ValueDisplay");
ConstantExpression conditionDisplayValue = Expression.Constant("UserName");
var conditionC = Expression.Equal(conditionDisplay, conditionDisplayValue);
MemberExpression conditionRow = Expression.Property(insideProperty, "RowNumber");
var newValueToCompare = Expression.PropertyOrField(baseProperty, "RowNumber");
ConstantExpression conditionRowValue = Expression.Constant(0);
var conditionD = Expression.Equal(conditionRow, newValueToCompare);
var condition = Expression.AndAlso(conditionA, conditionB);
var condition2 = Expression.AndAlso(conditionC, conditionD);
var condition3 = Expression.AndAlso(condition, condition2);
var predicate = Expression.Lambda<Func<MaterializedViewItem, bool>>(condition3, insideProperty);
var callCondtions = BuildAny<MaterializedViewItem>(predicate, MyDtoList.Expression);
var myPredicate = Expression.Lambda<Func<T, bool>>(callCondtions, baseProperty);
MemberExpression conditionCol2 = Expression.Property(insideProperty, "ColNumber");
ConstantExpression conditionCol2Value = Expression.Constant((byte)3);
var conditionE = Expression.Equal(conditionCol2, conditionCol2Value);
MemberExpression conditionColDisplay2 = Expression.Property(insideProperty, "ValueDisplay");
ConstantExpression conditionColDisplay2Value = Expression.Constant("2261");
var conditionF = Expression.Equal(conditionColDisplay2, conditionColDisplay2Value);
var condition22 = Expression.AndAlso(conditionA, conditionD);
var condition23 = Expression.AndAlso(conditionE, conditionF);
var condition2Final = Expression.AndAlso(condition22, condition23);
var predicate2 = Expression.Lambda<Func<T, bool>>(condition2Final, insideProperty);
var callCondtions2 = BuildAny<T>(predicate2, MyDtoList.Expression);
需要为我最终构建带有所有参数的Any功能
public static Expression BuildAny<T>(Expression<Func<T, bool>> predicate, Expression expression)
{
var overload = typeof(Queryable).GetMethods().FirstOrDefault(method => method.Name == "Any" && method.GetParameters().Count() == 2);
var specificMethod = overload.MakeGenericMethod(typeof(T));
var call = Expression.Call(
specificMethod,
expression,
predicate);
return call;
}
要记住的重要一点是,我们正在基于临时对象构建IQueryable。后来它不得不用真正的数据库表代替。可以通过以下方式完成:
IQueryable<T> queryList = this.DbSet;
var filtersForDbSet = ExpressionTreeConstantReplacer.CopyAndReplace<DbSet<T>, T>(condition, typeof(EnumerableQuery<T>), this.DbSet);
class ExpressionTreeConstantReplacer
{
internal static Expression<Func<T2, bool>> CopyAndReplace<T, T2>(Expression<Func<T2, bool>> expression, Type originalType, T replacementConstant)
{
var modifier = new ExpressionTreeConstantReplacer<T>(originalType, replacementConstant);
var newLambda = modifier.Visit(expression) as LambdaExpression;
return Expression.Lambda<Func<T2, bool>>(newLambda.Body, newLambda.Parameters.FirstOrDefault());
}
}
和
class ExpressionTreeConstantReplacer<T> : ExpressionVisitor
{
Type originalType;
T replacementConstant;
internal ExpressionTreeConstantReplacer(Type originalType, T replacementConstant)
{
this.originalType = originalType;
this.replacementConstant = replacementConstant;
}
protected override Expression VisitConstant(ConstantExpression c)
{
return c.Type == originalType ? Expression.Constant(replacementConstant) : c;
}
}
如果有人在表达式树中有类似的问题。查询的构建方式与普通查询相同。要将一些虚词从主表达式传递到内部表达式,您只需要证明您将它们进行比较即可:
MemberExpression conditionRow = Expression.Property(insideProperty, "RowNumber");
var newValueToCompare = Expression.PropertyOrField(baseProperty, "RowNumber");
var conditionD = Expression.Equal(conditionRow, newValueToCompare
答案 0 :(得分:1)
正如我在问题评论中提到的那样,您的查询可以简化。
[初始注释]
根据评论中的讨论,我认为您的查询仍然可以改进。
[版本1] -外观
SELECT DISTINCT ROW_NUMBER
FROM dbo.VIEW_ITEM item
WHERE CODE ='MyName'AND COL_NUMBER IN(1, 3) AND DISPLAY IN ('UserName', '2261')
ORDER BY ROW_NUMBER
根据您的SQL查询,Linq版本可能类似于:
int[] nums = {1, 3};
string[] disp = {"UserName", "2261"};
var result = dboMVI
.Where(mvi=> mvi.Code == 'MyName' &&
nums.Any(n=> n.Contains(mvi.ColNumber)) &&
disp.Any(d=> d.Contains(mvi.Display))
.OrderBy(x=>x.RowNumber)
.Select(x=>.RowNumber);
如果上述查询不符合您的条件,则尝试将条件与括号结合起来
[版本2] -外观
SELECT DISTINCT ROW_NUMBER
FROM dbo.VIEW_ITEM item
WHERE (CODE ='MyName'AND COL_NUMBER IN(1, 3)) AND
(CODE ='MyName' AND DISPLAY IN ('UserName', '2261'))
ORDER BY ROW_NUMBER
等效于Linq:
var result = dboMVI
.Where(mvi=> (mvi.Code == 'MyName' &&
nums.Any(n=> n.Contains(mvi.ColNumber))) &&
(mvi.Code == 'MyName' &&
disp.Any(d=> d.Contains(mvi.Display)))
.OrderBy(x=>x.RowNumber)
.Select(x=>.RowNumber);
如您所见,返回数据必须同时满足两个条件。
[EDIT#2]
关于表达式...我认为它应该像这样:
Expression<Func<ViewItem, string, int, string, bool>> filter = (mvi, code, colNo, disp) =>
dboMVI.Any(innerMvi =>
innerMvi.RowNumber == mvi.RowNumber &&
innerMvi.Code==code &&
innerMvi.ColNumber == colNo &&
innerMvi.Display == disp);
[最后的音符]
注意:我无法访问您的数据,并且我无法保证100%的上述查询将满足您的条件。