gpt4 book ai didi

c# - 针对多个字段的 LINQ string[]

转载 作者:太空狗 更新时间:2023-10-29 21:24:18 25 4
gpt4 key购买 nike

假设我有一个表 dataContext.Customer,其中包含以下字段

    FName    varchar
LName varchar
Phone varchar
DOB datetime
Address varchar

表格中充满了一些样本数据,假设:

    John | Smith | 3051112222 | 01/01/1978 | Roosevelt Av 787
Aron | Frank | 7871112222 | 01/01/1979 | Lambda Street 305
Dick | Bush | 9512221111 | 01/01/1980 | John Street 1
John | Allen | 7872222222 | 01/01/1981 | Liberty Av 555

我们还有一个包含任意数量元素的字符串数组,例如:

    search[0] = "1978"
search[1] = "John"

我需要一个 LINQ 查询,它将使用“contains”或“any”(在 SQL 中表示 LIKE)递增地将表的每个字段与字符串数组中的每个项目进行比较,并且只返回匹配所有给定条件的行一条记录,根据前面的搜索 [] 示例,LINQ 查询应该只返回记录 #1。

另一个例子可以是:

    search[0] = "Bush"
search[1] = "111"
search[2] = "John"

只有记录 #3 应该被返回。最后:

    search[0] = "John"

应该返回记录#1、#3和#4(我觉得思路很清晰)

有一个关于如何比较 string[] 和字段的问题: LINQ: Entity string field contains any of an array of strings

如果答案是 50 行 C# 例程,我更愿意通过存储过程直接在数据库中解决这个问题。

如果有某种“反射”技巧在执行查询时迭代 dataContext.Customers 上的所有字段,那将会很棒(显然真实表没有 5 个字段)。

性能不是问题。

我很确定这不能在单个 LINQ 行中完成,因为多重匹配需要逻辑,但问总不会有坏处,更不用说学习任何新东西了:)

更新:好的,这是完成任务的简单 SQL 代码。请注意,为了清楚起见,我已将搜索变量的数量减少到 2 个。在现实生活场景中,我们可以将参数数量限制为 10 个搜索参数。我故意不使用函数(好吧,CONVERT 除外)以使 SQL 尽可能简单,以查看是否有任何方法可以在 LINQ 中完成此操作。这是 SQL:

    declare @_SEARCH1 varchar(1000)
select @_SEARCH1 = 'John'
declare @_SEARCH2 varchar(1000)
select @_SEARCH2 = '111'

select *
from CUSTOMER
where
FName + ' ' + LName + ' ' + Phone + ' ' + CONVERT(varchar, DOB, 101) + ' ' + Address like '%'+@_SEARCH1+'%'
and FName + ' ' + LName + ' ' + Phone + ' ' + CONVERT(varchar, DOB, 101) + ' ' + Address like '%'+@_SEARCH2+'%'

所以问题是,有没有办法编写一个 LINQ 来生成这个简单的 SQL? (请注意,比较是通过“LIKE”在数据库中完成的,而不是在应用程序中完成的)

更新 2:尽管 Francisco 的解决方案会生成“LIKE”语句,但它无法进行比较。将所有数据从表中提取到网络服务器的其他解决方案将正确匹配,但完全不切实际。

已接受对 RUNE FS 的回答,因为它是最干净的解决方案,并且适用于任何数量的字段。

最佳答案

使用 PredicateBuilder

void Main()
{
var search = new string[] { "Romania","RO"};
var query = from c in countries.AllAny(search)
orderby c.name
select c;
query.Dump();
}

public static class QueryExtensions
{
public static IQueryable<T> AllAny<T>(this IQueryable<T> query, string[] search)
{
var properties = typeof(T).GetProperties().Where(p => p.GetCustomAttributes(typeof(System.Data.Linq.Mapping.ColumnAttribute),true).Any()).Select(n=>n.Name);
var andPredicate = PredicateBuilder.True<T>();
foreach ( var term in search )
{
var orPredicate = PredicateBuilder.False<T>();
foreach (var property in properties )
orPredicate = orPredicate.Or(CreateLike<T>(property,term));
andPredicate = andPredicate.And(orPredicate);
}
return query.Where(andPredicate);
}
private static Expression<Func<T,bool>> CreateLike<T>( PropertyInfo prop, string value)
{
var parameter = Expression.Parameter(typeof(T), "f");
var propertyAccess = Expression.MakeMemberAccess(parameter, prop);
var toString = Expression.Call(propertyAccess, "ToString", null, null);
var like = Expression.Call(toString, "Contains", null, Expression.Constant(value,typeof(string)));

return Expression.Lambda<Func<T, bool>>(like, parameter);
}

private static Expression<Func<T,bool>> CreateLike<T>( string propertyName, string value)
{
var prop = typeof(T).GetProperty(propertyName);
return CreateLike<T>(prop, value);
}

}

// http://www.albahari.com/nutshell/predicatebuilder.aspx
public static class PredicateBuilder
{
public static Expression<Func<T, bool>> True<T> () { return f => true; }
public static Expression<Func<T, bool>> False<T> () { return f => false; }

public static Expression<Func<T, bool>> Or<T> (this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
return Expression.Lambda<Func<T, bool>>
(Expression.OrElse (expr1.Body, invokedExpr), expr1.Parameters);
}

public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
return Expression.Lambda<Func<T, bool>>
(Expression.AndAlso (expr1.Body, invokedExpr), expr1.Parameters);
}
}

更新此代码是以下查询的通用解决方案

from c in countries
where (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]))
/*&& ...*/
orderby c.name
select c

此代码可以通过多种方式进行改进。例如,对于字符串属性,无需在 Contains 之前调用 ToString(这将生成一个 convert(nvarchar)),我真的认为需要它的人只想查看 varchar、nvarchar 列。

关于c# - 针对多个字段的 LINQ string[],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7087496/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com