我写的是我认为应该是一个相对简单的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;)'的类型参数。尝试明确指定类型参数。
答案 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();