LINQstringformultiplefields假设我有一个表dataContext.Customer具有以下字段FNamevarcharLNamevarcharPhonevarcharDOBdatetimeAddressvarchar该表填充了一些示例数据,假设:John|史密斯|3051112222|1978年1月1日|罗斯福Av787阿伦|弗兰克|7871112222|1979年1月1日|Lambda街305迪克|约翰|艾伦|7872222222|1981年1月1日|LibertyAv555我们还有一个包含任意数量元素的字符串数组,例如:search[0]="1978"search[1]="John"我需要一个LINQ查询,它将递增地比较表的每个字段字符串数组中的每个项目使用“contains”或“any”(在SQL中表示LIKE)并仅返回匹配记录中所有给定条件的行,基于前面的search[]示例,LINQ查询应仅返回记录#1。另一个例子可能是:search[0]="Bush"search[1]="111"search[2]="John"并且只返回记录#3。最后:search[0]="John"records#1,#3and#4shouldbereturned(我觉得思路很清晰)有个问题是如何比较string[]和fields:LINQ:EntityStringFieldContains任何字符串数组如果答案是50行C#例程,我更愿意通过存储过程直接在数据库中解决这个问题。如果在执行查询时有一些“反射”技巧来遍历dataContext.Customers上的所有字段(显然真正的表没有5个字段),那就太棒了。性能不是问题。我很确定这不能在单个LINQ系列中完成,因为多个匹配需要逻辑,但问题永远不会伤害,更不用说学习任何新东西了:)更新:好的,这是一个完成任务的简单SQL代码。请注意,为清楚起见,我已将搜索变量的数量减少到2个。在现实生活中,我们可以将参数的数量限制为10个搜索参数。我故意不使用函数(当然,CONVERT除外)来使SQL尽可能简单,以查看是否有任何方法可以在LINQ中执行此操作。下面是SQL:declare@_SEARCH1varchar(1000)select@_SEARCH1='John'declare@_SEARCH2varchar(1000)select@_SEARCH2='111'select*fromCUSTOMERwhereFName+''+LName+''+Phone+''+CONVERT(varchar,DOB,101)+''+Addresslike'%'+@_SEARCH1+'%'andFName+''+LName+''+Phone+''+CONVERT(varchar,DOB,101)+''+Addresslike'%'+@_SEARCH2+'%'所以问题是,有没有办法编写一个LINQ来生成这个简单的SQL?(请注意,比较是通过“LIKE”在数据库中完成的,而不是在应用程序中完成的)更新2:虽然像Francisco的解决方案会生成“LIKE”语句,但它无法进行比较。将表中的所有数据提取到Web服务器的其他解决方案将正确匹配,但完全不切实际。RUNEFS接受的答案是最干净的解决方案,适用于任何领域。假设“t”永远不会成为数据的一部分,您可以执行以下操作。您当然可以替换任何其他字符。有了这个假设,你可以这样做:;按顺序从s返回))选择s;编辑我最初没有包括用法,因为我没有在原始帖子中找到任何集合,但假设序列被定义为IEnumerabl并且可以作为变量db上的Persons属性访问。代码看起来像是:IEnumerablepersons=db.Persons.Where(criteria);使用PredicateBuildervoidMain(){varsearch=newstring[]{"Romania","RO"};varquery=fromcincountries.AllAny(search)orderbyc.nameselectc;查询.转储();}publicstaticclassQueryExtensions{publicstaticIQueryableAllAny(这个IQueryable查询,字符串[]搜索){varproperties=typeof(T).GetProperties().Where(p=>p.GetCustomAttributes(typeof(System.Data.Linq.Mapping.ColumnAttribute),true).Any()).Select(n=>n.Name);varandPredicate=PredicateBuilder.True();foreach(varterminsearch){varorPredicate=PredicateBuilder.False();foreach(varpropertyinproperties)orPredicate=orPredicate.Or(CreateLike(property,term));andPredicate=andPredicate.And(orPredicate);}returnquery.Where(andPredicate);}privatestaticExpression>CreateLike(PropertyInfoprop,stringvalue){varparameter=Expression.Parameter(typeof(T),"f");varpropertyAccess=表达式.MakeMemberAccess(参数,道具);vartoString=Expression.Call(propertyAccess,"ToString",null,null);varlike=Expression.Call(toString,"Contains",null,Expression.Constant(value,typeof(string)));返回Expression.Lambda>(例如,参数);}privatestaticExpression>CreateLike(stringpropertyName,stringvalue){varprop=typeof(T).GetProperty(propertyName);返回CreateLike(prop,value);}}//http://www.albahari.com/nutshell/predicatebuilder.aspxpublicstaticclassPredicateBuilder{publicstaticExpression>True(){returnf=>true;}publicstaticExpression>False(){returnf=>false;}publicstaticExpression>Or(thisExpression>expr1,Expression>expr2){varinvokedExpr=Expression.Invoke(expr2,expr1.Parameters.Cast());returnExpression.Lambda>(Expression.OrElse(expr1.Body,invokedExpr),expr1.Parameters);}publicstaticExpression>And(thisExpression>expr1,Expression>expr2){varinvokedExpr=Expression.Invoke(expr2,expr1.Parameters.Cast());returnExpression.Lambda>(Expression.AndAlso(expr1.Body,invokedExpr),expr1.Parameters);}}UPDATE此代码是以下国家/地区c查询的通用解决方案,其中(c.name.ToString().Contains(search[0])||c.name.ToString().Contains(search[1]))&&(c.iso_code.ToString().Contains(search[0])||c.iso_code.ToString().Contains(search[1]))/*&&...*/orderbyc.nameselectc这段代码可以在几个方面改进例如,对于字符String属性,不需要在Contains之前调用ToString(这将生成convert(nvarchar)),我真的认为需要这个的人只想看看varchar,nvarchar列。我不认为linqtosql可以有效地做到这一点,但linqtoobjects可能会有所帮助,如果你可以通过应用程序代码和数据库之间的线路移动整个表,一次一个搜索。第一步是获取将读取表中所有记录的DataReader。使用数据读取器很重要,因为您可能不想用整个表填充内存(然后,也许您会这样做-请参阅我关于缓存附近的缓存的说明)。完成后,需要将其转换为IEnumerable以便与linq-to-objects一起使用。您可以使用像这样的简单的两行实用程序方法来完成此操作:IEnumerableEnumerableFromDataReader(IDataReaderreader){while(reader.Read())yieldreturnreader;我通常使用的实际代码有点复杂,但我所做的可能与您项目其余部分的结构不太一致,所以我暂时将这个简短的方法留给那个。一旦我们有了Enumerable,我们就可以利用linq的可组合特性来获得一些(相对)简单(或至少简短)的代码,如下所示:IEnumerableSearchMyTable(string[]filters){varresults=EnumerableFromDataReader(GetMyTable());foreach(过滤器中的字符串过滤器){results=results.Where(r=>String.Join("",r.GetValues().Cast().ToArray()).Contains(filter));}返回结果;它不是单个linq查询,但也不是50行代码。忽略网络延迟,这段代码的性能实际上相当不错。如果你想在列连接后对表的全部或部分进行一些缓存,性能会非常惊人。更新:此代码中(至少)存在一个缺陷。对于每个过滤器,我将所有保留到该过滤器的行转换回字符串……即使我已经为以前的过滤器完成了此操作。解决这个问题的方法是首先执行投影以将行与字符串版本配对。但是在我的时间晚上11点之后,我将保留代码,因为它代表了现在。好消息是最终的固定代码应该是相同的长度:只需在第一行和最后一行添加一个.Select()调用,并稍微更改foreach循环的中间部分。我现在手边没有C#编译器,但我有这个想法:声明一个lambda表达式,如下所示:publicExpression>GetFilterFromString(stringinput){returnp=>p.FName.Contains(input)||p.LName.包含(输入)||p.Phone.Contains(输入)||p.DOB.ToString().Contains(输入)||p.Address.Contains(输入)||实现可能会根据您的需要而有所不同(例如连接所有字段,就像您对SQL查询所做的那样)。然后在您的主要查询功能中:IQueryablecustomers=dataContext.Customers;foreach(stringinputSearchinsearch){customers=customers.Where(GetFilterFromString(inputSearch));}IEnumerable结果=customers.AsEnumerable();我认为这种方法的主要优点是您必须声明一次GetFilterFromString。希望这就是您要找的。编辑:好的,所以我读了你正在寻找的SQL语句(有点晚了......但无论如何)。我认为调整我的解决方案很容易。我们将不得不稍微调整lambda表达式:publicExpression>GetFilterFromString(stringinput){returnp=>(p.FName+""+p.LName+""+p.Phone+""+p.DOB.ToString()+""+p.Address).Contains(input)}可能我可能会做的是,首先我将数据库中的记录与我拥有的数组项进行比较。一旦我得到表数据的一个子集(假设数据库表的结构相同,数组结构也意味着数组[0]始终是名称),然后我在内存中搜索我正在寻找的模式。我相信这不是您所希望的完整解决方案。但是,让我进一步思考,意味着我愿意接受更多的想法,伙计们:)类似于Francisco的回答,但只有一个where子句的应用:以上是C#学习教程的全部内容:LINQstringSharedagainstMultipleFieldsContent,如果对你有用,需要多了解C#学习教程,希望大家多多关注—string[]search=newstring[]{"Bush","111","John"};varcustomers=new[]{new{FName="Dick",Surname="Bush",Phone="9512221111",DOB=newDateTime(1980,01,01),Address="JohnStreet1"},new{FName="John",Surname="Smith",Phone="3051112222",DOB=newDateTime(1978,01,01),Address="RooseveltAv787"}};var结果=customers.Where(customer=>search.All(term=>customer.FName.Contains(term)||customer.Surname.Contains(term)||customer.DOB.ToString().Contains(term)||customer.Phone.Contains(term)||customer.Address.Contains(term)));本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
