我正在尝试创建一个动态linq查询,该查询将根据字符串检查值。
首先,这是查询:
objQry = from o in m_Db.OBJECTS.Where(whereConditions)
select o;
if(!objQry.Any())
{
return null;
}
whereConditions
变量是我构建的字符串,并作为参数传递以找出我需要的值。以下是有效字符串的示例:
OBJ_NAME == \"Sword\" and OBJ_OWNER == \"Stan\"
这将返回名称为“Sword”且所有者为“Stan;
OBJ_COLOR == \"Blue\" OR OBJ_COLOR == \"Red\"
这将返回任何颜色为蓝色或红色的项目。
到那里,我很好,但现在我有一个问题:我需要检查十进制字段。所以我试过这个字符串:
OBJ_NUMBER == 1
但即使存在OBJ_NUMBER值为1的对象,查询也会返回null。它是小数。如何指出需要检查十进制值的查询?
****编辑****
我试图“修改”传递的值,使其看起来像这样:
"CARD_NUMBER == Convert.ToDecimal(1)"
现在我有一种不同的错误告诉我:
LINQ to Entities does not recognize the method 'System.Decimal ToDecimal(Int32)' method, and this method cannot be translated into a store expression.
有人提出任何线索吗?我还在寻找一种方法来做到这一点。谢谢!
编辑2
您可以通过查看this question来了解我的代码的形成示例。
让我们回过头来看看这个问题。我想检查小数值。假设OBJ_NUMBER是一个十进制字段。
使用Dynamic Linq
,我尝试读取十进制字段。假设我想得到每个对象的数字是1.27。 whereConditions
字段的形状如下:
OBJ_NUMBER == 1.27
但是我会收到Invalid real literal '1.27'
错误。我不知道为什么。
所以我尝试过Gert Arnold的解决方案,而不是这样做:
decimal bDecimal = decimal.Parce(valueToParse);
param = new ObjectParameter("cardNumber", typeof(decimal)) { Value = bDecimal };
valuesToUse.Add("CARD_NUMBER == @cardNumber");
listParams.Add(param);
但我最终遇到了两个问题:
第一个问题是我的whereConditions
字符串是这样形成的:
CARD_NUMBER == @cardNumber
但是我收到以下错误:
No property or field 'cardNumber' exists in type 'CARD'
让我相信它无法在object参数和用于执行查询的字符串之间建立链接。
如您所见,我有一个Params列表。这是因为我无法确定用户将选择多少参数。因此,每次用户输入新的搜索字段时,我都必须创建一个新的ObjectParameter并将其存储在列表中。以下是我尝试做之后的事情:
ObjectParameter[] arrayParameters = listParams.ToArray();
// Convert the list to an array
然后,当我尝试进行查询时:
cardQry = from c in mDb.CARD.Where(whereConditions, arrayParameters)
select c;
但无济于事。
结果
根据下面回答的问题,我发展了一些“糟糕”但功能正常的东西。
首先,我忽略每个十进制字段,因为我永远无法使用动态linq到达它们。相反,我这样做:
var valuesToParse = keyValuePair.Value.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries);
// Here I parse the value and, if that's the case, the symbol.
decimal baseValue = decimal.Parse(valuesToParse[0]);
if (valuesToParse.Count() > 1)
{
string baseMethod = valuesToParse[1];
if (baseMethod == ">" || baseMethod == ">=")
{
if (baseMethod == ">=")
{
baseValue--;
}
// The list is actually like this: Dictionary<string, object> list = new Dictionary<string, object>();
list.Add("low", baseValue);
// I kind of activate a tag telling me that the user is looking for a higher value.
cardHigher = true;
}
else
{
if (baseMethod == "<=")
{
baseValue++;
}
list.Add("low", baseValue);
cardLower = true;
}
}
else
{
//lowParam = new ObjectParameter("dec", typeof(decimal)) { Value = baseValue };
list.Add("low", baseValue);
}
cardNumberActivated = true;
最后,当我得到对象列表时,我这样做:
if (list.Count > 0)
{
(example)
if (cardNumberActivated)
{
if (cardHigher)
{
q = mDb.CARD.Where("CARD_NUMBER >= @0", list["low"]).ToList();
}
else if (cardLower)
{
q = mDb.CARD.Where("CARD_NUMBER <= @0", list["low"]).ToList();
}
else
{
q = mDb.CARD.Where("CARD_NUMBER == @0", list["low"]).ToList();
}
}
}
// Here we get the orinalData with the basic filters.
listToReturn.AddRange(cardQry);
if (q != null)
{
//listToReturn.AddRange(q);
for (int i = 0; i < listToReturn.Count; i++)
{
var priceList1 = listToReturn[i];
if (!q.Any(_item => _item.CARD_NUMBER == priceList1.CARD_NUMBER))
{
listToReturn.RemoveAt(i);
i--;
}
}
}
它有效。这是不一种优雅的方式使它工作,但我可以按照我想要的方式验证字段,为此,我终于感恩了。
答案 0 :(得分:1)
您不应构建具有内联谓词值的查询字符串。请使用参数。然后还可以指定类型:
var whereConditions= "it.CARD_NUMBER = @cardNumber";
var param = new ObjectParameter("cardNumber", typeof(decimal)) { Value = 1 };
objQry = from o in m_Db.OBJECTS.Where(whereConditions, param);
修改强>
我不知道你的代码中有什么不起作用。这里只是一个随机的工作代码,来自我自己的一个项目:
var param1 = new ObjectParameter("dec", typeof(decimal)) { Value = 90000m };
var param2 = new ObjectParameter("int", typeof(int)) { Value = 90000 };
var q = ValueHolders.Where("it.DecimalValue >= @dec OR it.IntegerValue > @int",
param1, param2).ToList();
请注意,param1, param2
也可以是ObjectParameter
的数组。