【问题标题】:Use a numeric value in a linq dynamic query string在 linq 动态查询字符串中使用数值
【发布时间】:2013-04-17 17:06:55
【问题描述】:

我正在尝试进行动态 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);

但我最终遇到了两个问题:

  1. 第一个问题是我的whereConditions 字符串是这样形成的:

    CARD_NUMBER == @cardNumber

    但我收到以下错误:

    No property or field 'cardNumber' exists in type 'CARD'

    让我相信它无法在对象参数和用于查询的字符串之间建立联系。

  2. 如您所见,我有一个参数列表。这是因为我无法确定用户将选择多少个参数。所以每次用户输入一个新的搜索字段时,我都必须创建一个新的 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--;
        }
    }
}

而且它有效。这不是使其工作的优雅方式,但我可以按照我想要的方式验证字段,为此,我最后很感激。

【问题讨论】:

  • 现在,我没有尝试,我会这样做并告诉你结果。
  • 不,这会引发“语法”错误。
  • 同样的结果。好像有什么不对劲。也许将值放在引号中?
  • 我曾尝试将值放在双引号中,但现在我最终遇到“运算符与操作数类型十进制和字符串不兼容”错误...:/

标签: c# linq decimal dynamic-linq


【解决方案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 的数组。

【讨论】:

  • 抱歉回复晚了。我有一个问题问你。如果我真的想得到所有卡号大于1的卡怎么办?有可能做到吗?
  • 回复晚的原因是我这个时候放弃了这个问题,但现在又回来困扰我,所以我必须努力解决它。 ^^
  • 如果我必须堆叠许多值怎么办?如果我添加查找任何卡号大于 1 的剑怎么办?
  • @HerveS 您可以使用其他运算符,例如&gt; 以及更多带有ANDOR 的谓词。
  • 好的,我试试这个。现在我的问题在于堆叠许多 ObjectParameters,我该怎么做?
猜你喜欢
  • 1970-01-01
  • 2023-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-19
  • 2021-02-06
  • 1970-01-01
相关资源
最近更新 更多