C# 使用LINQ的多个搜索参数
我正在写我认为应该是一个相对简单的Windows窗体应用程序。我正在使用LINQtoSQL,尽管我以前从未使用过它。我们有一个SQL Server数据库,我正在创建一个前端来访问该数据库。我正试图找出用它搜索多个(任意数量)搜索参数的最有效方法 在windows窗体中,我用每个搜索键及其要搜索的值创建了一个字典,并将其传递到我的search()方法中。我试图找到一种方法来搜索数据库中的每个键及其相关值。以下是我试图做的:C# 使用LINQ的多个搜索参数,c#,linq-to-sql,C#,Linq To Sql,我正在写我认为应该是一个相对简单的Windows窗体应用程序。我正在使用LINQtoSQL,尽管我以前从未使用过它。我们有一个SQL Server数据库,我正在创建一个前端来访问该数据库。我正试图找出用它搜索多个(任意数量)搜索参数的最有效方法 在windows窗体中,我用每个搜索键及其要搜索的值创建了一个字典,并将其传递到我的search()方法中。我试图找到一种方法来搜索数据库中的每个键及其相关值。以下是我试图做的: public IQueryable<Product> Sear
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;
}
公共可查询搜索(字典搜索参数)
{
DBDataContext dc=新的DBDataContext();
var query=dc.Products;
foreach(searchParams中的KeyValuePair临时值)
{
查询=查询,其中(x=>x.(临时键)=临时值);
}
返回查询;
}
我意识到语法上的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;
}
公共可查询搜索(字典搜索参数)
{
DBDataContext dc=新的DBDataContext();
字符串sQuery=“”;
foreach(searchParams中的KeyValuePair临时值)
{
sQuery+=临时键+“=”+临时值+”和“;
}
var query=dc.Products.Where(sQuery);
返回查询;
}
根据LINQ动态查询库的文章,这应该是可以的。下面是我得到的错误:
无法根据用法推断方法“System.Linq.Queryable.Where(System.Linq.IQueryable,System.Linq.Expressions.Expression>)”的类型参数。请尝试显式指定类型参数。如果出于某种原因不需要词典,我将按如下方式创建您的搜索方法:
public IQueryable<Product> Search( Func<Product, bool> isMatch )
{
DBDataContext dc = new DBDataContext();
return dc.Products.Where( isMatch ).AsQueryable();
}
你有什么理由不能那样做吗
[编辑:添加了AsQueryable()]
[编辑:用于使用字符串的动态查询]
看看这里,看看这是否有帮助。我没用过,但看起来这正是你想要的:
就个人而言,我通常更喜欢类型安全表达式>方法,因为这会给您带来编译时错误……但是如果需要字符串,那么看起来是最好的方法
根据以上链接,您应该能够执行以下操作:
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;
}
公共可查询搜索(字典搜索参数)
{
DBDataContext dc=新的DBDataContext();
StringBuilder sQuery=新的StringBuilder();
foreach(searchParams中的KeyValuePair临时值)
{
如果(sQuery.Length>0)sQuery.Append(“AND”);
追加格式(“{0}={1}”,临时键,临时值);
}
var query=dc.Products.Where(sQuery.ToString());
返回查询;
}
这将仅在第一次之后的条件下使用“和”。希望对你有帮助
仅供参考-这不是主题,但是“为什么”我使用StringBuilder是因为字符串连接的方式会导致字符串被销毁,并且每个循环在内存中创建4次新字符串…因此改为StringBuilder,因为这将创建一个缓冲区,只有在必要时才可以填充和调整大小。而不是使用字典,您可以使用以下方法:
using System.Linq.Expressions;
// ...
public static IQueryable<Product> Search(Expression<Func<Product, bool>> search)
{
DBDataContext dc = new DBDataContext();
return dc.Products.Where(search);
}
您也不会局限于字符串属性。下面是一个使用
你试过为你的字符串加上单引号吗? 根据您的foreach循环,在查询的末尾将有额外的“AND” 试试这个
string sQuery = searchParam.Select(entry => string.Format("{0} = '{1}'", entry.Key, entry.Value)).Aggregate((current, next) => current + " AND " next);
如果您愿意创建一个可搜索术语词典,那么我已经使用了类似下面的方法。我已经调整了我所做的事情,使之更符合您的工作方式,我还更改了表的名称,以适合我可用的datacontext/对象模型 这样做的目的是创建一个关键字列表,您的查询支持按其进行搜索。然后添加返回表达式的函数,该表达式可以传递到查询的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;
}
公共可查询搜索(字典搜索参数)
{
DBDataContext dc=新的DBDataContext();
var query=dc.Persons.Where(p=>true);//执行“空谓词”,因为您希望“query”是iqueryable而不是表
//建立一个列表,列出你可以过滤的事物类型。
var criteriaDefinitions=新字典();
添加(“FirstName”,s=>p=>p.FirstName==s);
添加(“LastName”,s=>p=>p.LastName==s);
//你可以做一些不只是相等的运算
添加(“EmailContains”,s=>p=>p.Email.Contains);
//您甚至可以创建集成联接的表达式。
添加(“HasContactInCity”,s=>p=>p.Contacts.Any(c=>c.City==s));
foreach(searchParams中的KeyValuePair临时值)
{
//从字典中找出正确的函数
var func=标准定义[temp.Key];
//对函数求值将返回一个表达式,该表达式可以传递到where子句中。
变量表达式=函数(温度值);
query=query.Where(expr);
}
返回查询;
}
用于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();
搜索方法参数需要是一个字典而不是一个Func,这有什么原因吗???不完全确定这是什么意思。。。你能澄清一下吗?字典里的每一个键都有段落
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
string sQuery = searchParam.Select(entry => string.Format("{0} = '{1}'", entry.Key, entry.Value)).Aggregate((current, next) => current + " AND " next);
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;
}
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();