在linq动态查询字符串中使用数值

时间:2013-04-17 17:06:55

标签: c# linq decimal dynamic-linq

我正在尝试创建一个动态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'

    让我相信它无法在object参数和用于执行查询的字符串之间建立链接。

  2. 如您所见,我有一个Params列表。这是因为我无法确定用户将选择多少参数。因此,每次用户输入新的搜索字段时,我都必须创建一个新的ObjectParameter并将其存储在列表中。以下是我尝试做之后的事情:

    ObjectParameter[] arrayParameters = listParams.ToArray(); // Convert the list to an array

  3. 然后,当我尝试进行查询时:

    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--;
            }
        }
    }
    

    它有效。这是一种优雅的方式使它工作,但我可以按照我想要的方式验证字段,为此,我终于感恩了。

1 个答案:

答案 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的数组。