使用LINQ的多个搜索参数

时间:2010-10-28 18:25:15

标签: c# linq-to-sql

我写的是我认为应该是一个相对简单的Windows窗体应用程序。我正在使用LINQ to SQL,尽管我之前从未使用过它。我们有一个SQL Server数据库,我正在创建一个访问该数据库的前端。我正试图找出用它搜索多个(任意数量)搜索参数的最有效方法。

在windows窗体中,我创建了一个字典,其中包含每个搜索键及其要搜索的值,并将其传递给我的search()方法。我试图找到一种方法来搜索数据库中的每个键及其相关值。这是我想要做的:

public IQueryable<Product> Search(Dictionary<string, string> searchParams)
{
   DBDataContext dc = new DBDataContext();
   var query = dc.Products;

   foreach (KeyValuePair<string, string> temp in searchParams)
   {
      query = query.Where(x => x.(temp.Key) == temp.Value);
   }

   return query;
}

我意识到语法上的x。(temp.Key)是不正确的,但我希望这说明了我要做的事情。我想知道是否还有另一种方法可以解决我想要做的事情,而不必做一个巨大的switch语句(或者if / else if tree)。

修改

所以,我修改了一下,但我仍然遇到问题。这是我现在拥有的:

public IQueryable<Product> Search(Dictionary<string, string> searchParams)
{
    DBDataContext dc = new DBDataContext();

    string sQuery = "";
    foreach (KeyValuePair<string, string> temp in searchParams)
    {
        sQuery += temp.Key + "=" + temp.Value + " AND ";
    }

    var query = dc.Products.Where(sQuery);

    return query;
}

根据LINQ Dynamic Query Library的文章,这应该没问题。这是我得到的错误:

无法从用法推断出方法'System.Linq.Queryable.Where(System.Linq.IQueryable,System.Linq.Expressions.Expression&gt;)'的类型参数。尝试明确指定类型参数。

6 个答案:

答案 0 :(得分:3)

这是一个有效的例子(我刚测试过),使用Dynamic LINQ Query Library

using System.Linq.Dynamic;
// ...

Dictionary<string, string> searchParams = new Dictionary<string,string>();

searchParams.Add("EmployeeID", "78");
searchParams.Add("EmpType", "\"my emp type\"");

IQueryable<Employee> query = context.Employees;

foreach (KeyValuePair<string, string> keyValuePair in searchParams)
{
    query = query.Where(string.Format("{0} = {1}", keyValuePair.Key,  keyValuePair.Value));
}

List<Employee> employees = query.ToList();

并且,为了使绝对清晰,此代码实际上,这里是实际生成的SQL:

FROM [HumanResources].[Employee] AS [t0]
WHERE ([t0].[EmpType] = @p0) AND ([t0].[EmployeeID] = @p1)',N'@p0 nvarchar(11),@p1 int',@p0=N'my emp type',@p1=78

答案 1 :(得分:2)

如果出于某种原因不需要字典,我会按照以下方式制作您的搜索方法:

public IQueryable<Product> Search( Func<Product, bool> isMatch )
{
   DBDataContext dc = new DBDataContext();
   return dc.Products.Where( isMatch ).AsQueryable();
}

然后,您将使用如下方法:

Obj.Search( item => item.Property1 == "Hello" && item.Property2 == "World" );

你有什么理由不能这样做吗?

[编辑:添加了AsQueryable()]

[编辑:使用字符串进行动态查询]

看看这里,看看这是否有帮助。我还没有用它,但看起来就像你在寻找它: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

就个人而言,我通常更喜欢类型安全的表达式&gt;方法,因为这将给你编译时错误...但如果需要字符串,那么看起来是最好的方法。

基于上面的链接,看起来你应该可以做到:

query = query.Where( String.Format("{0}={1}",dict.Key,dict.Value) );

[编辑:字符串构建示例]

所以,其中一个问题是你的sql查询将以字符串末尾的AND结束,但之后没有条件......所以,可能会尝试更改为...语法可能会关闭稍微,但应该是对的:

public IQueryable<Product> Search(Dictionary<string, string> searchParams)
{
    DBDataContext dc = new DBDataContext();

    StringBuilder sQuery = new StringBuilder();
    foreach (KeyValuePair<string, string> temp in searchParams)
    {
        if( sQuery.Length > 0 ) sQuery.Append(" AND ");
        sQuery.AppendFormat("{0}={1}",temp.Key,temp.Value);
    }

    var query = dc.Products.Where(sQuery.ToString());

    return query;
}

这只会在第一个之后的条件下使用“AND”。希望它有所帮助...

仅供参考 - 这是偏离主题的,但'为什么'我使用StringBuilder是字符串连接的方式,它会导致字符串被销毁,并且每个循环在内存中创建一个新字符串...所以更改到StringBuilder,因为这将创建一个可以填充的缓冲区,只在必要时调整大小。

答案 2 :(得分:0)

您可以使用此方法代替使用字典:

using System.Linq.Expressions;
// ...

public static IQueryable<Product> Search(Expression<Func<Product, bool>> search)
{
    DBDataContext dc = new DBDataContext();
    return dc.Products.Where(search);
}

你可以像这样使用它:

Search(p => p.Name == "Name" && p.Id == 0);

您也不仅限于字符串属性。

答案 3 :(得分:0)

你试试为你的字符串单引号吗? 根据你的foreach循环,在查询结束时会有额外的'AND'

试试这个

string sQuery = searchParam.Select(entry => string.Format("{0} = '{1}'", entry.Key, entry.Value)).Aggregate((current, next) => current + " AND " next);

答案 4 :(得分:0)

如果你愿意创建一个可搜索术语的字典,而不是使用接近下面方法的东西。我已经调整了我更接近你的工作方式,我也改变了表格的名称以适应我可以使用的datacontext / object模型。

我们的想法是创建一个您的查询支持搜索的键控列表。然后添加返回表达式的函数,然后将其传递给查询的where子句。

您当然应该为无效密钥等添加一些错误处理。

public IQueryable<Person> Search(Dictionary<string, string> searchParams)
{
    DBDataContext dc = new DBDataContext();
    var query = dc.Persons.Where(p => true); //do an 'empty predicate' because you want 'query' to be an iqueryable<Person> not a Table<Person>

    //build a list of the types of things you can filter on.
    var criteriaDefinitions = new Dictionary<string,Func<string,Expression<Func<Person,bool>>>>();
    criteriaDefinitions.Add("FirstName",s => p => p.FirstName == s);
    criteriaDefinitions.Add("LastName",s => p => p.LastName == s);

    //you can do operations other than just equals
    criteriaDefinitions.Add("EmailContains",s => p => p.Email.Contains(s));

    //you can even create expressions that integrate joins.
    criteriaDefinitions.Add("HasContactInCity",s => p => p.Contacts.Any(c => c.City == s));


    foreach (KeyValuePair<string, string> temp in searchParams)
    {
        //grab the correct function out of the dictionary
        var func = criteriaDefinitions[temp.Key];

        //evaluating the function will return an expression which can passed into the where clause.
        var expr = func(temp.Value);
        query = query.Where(expr);
    }

    return query;
}

答案 5 :(得分:0)

用于linq搜索查询多个可选参数 可以使用此代码:

var query = dx.GetAllJobs().Where(x => x.JobName.Contains(keyword));

if (SecLink != 0)
{
    query = query.Where(x => x.SectorLink.Equals(SecLink));
}

if (LocLink != 0)
{
    query = query.Where(x => x.LocationLink.Equals(LocLink));
}

if (IndLink != 0)
{
    query = query.Where(x => x.IndustryLink.Equals(IndLink));
}

if (VacLink != 0)
{
    query = query.Where(x => x.VacancyTypeLink.Equals(VacLink));
}

var lstJobs = query.ToList();