我正在使用EntityFrameworkCore,并尝试创建一个简化实例,根据搜索对象是否包含通配符来搜索“等于”或“喜欢”。 这是我正在工作的基础
public class Person
{
public string Name;
public string MothersName;
public string FathersName;
}
public class SearchPerson
{
public string Name;
}
public class Program
{
public void FindPerson(SearchPerson searchPerson)
{
if (!string.IsNullOrEmpty(searchPerson.Name))
{
if (searchPerson.Name.Contains("%"))
{
EFPersonObject.Where(m => EF.Functions.Like(m.Name, searchPerson.Name));
}
else
{
EFPersonObject.Where(m => m.Name == searchPerson.Name);
}
}
}
}
如果我的SearchPerson类扩展到5或10或15个可能的搜索参数,则有很多重复的代码。我应该能够在扩展中实现一些反射,并使用Jim C的响应here,获取和传递属性的名称,并将其中的大部分简化为一行
public static class SearchExtension
{
public static void FindLike<T>(this DbSet<T> model, PropertyInfo info, string searchValue) where T : class
{
if (!string.IsNullOrEmpty(searchValue))
{
if (searchValue.Contains("%"))
{
model.Where(m => EF.Functions.Like(typeof(T).GetProperty(info.Name).GetValue(model, null).ToString(), searchValue));
}
else
{
model.Where(m => typeof(T).GetProperty(info.Name).GetValue(model, null).ToString() == searchValue);
}
}
}
}
用法:
EFPersonObject.FindLike(typeof(Person).GetProperty(RemoteMgr.GetPropertyName(()=>typeof(Person).Name)), searchPerson.Name);
(我还没有测试过,但是如果它不正确,应该就可以了),但是我假设我会在性能上受到打击。在不需要反射以避免性能下降的情况下,还有另一种方法可以实现此目标吗?
答案 0 :(得分:2)
在查询表达式树内使用反射(和其他非SQL可翻译的)调用不是一个好主意。在EF Core 1x和2.x中,它将引起客户端评估,并且EF Core v3 +将引发类似于EF 6的异常。
LINQ to Entities最好与表达式配合使用。并且,一旦需要表达式,最好使自定义扩展方法直接接收lambda表达式,而不要像链接主题中那样通过lambda表达式获得PropertyInfo
。
以下是上述示例的实现:
public static partial class QueryableExtensions
{
public static IQueryable<T> WhereMatch<T>(this IQueryable<T> source, Expression<Func<T, string>> expr, string searchValue)
{
if (string.IsNullOrEmpty(searchValue))
return source;
else if (searchValue.Contains("%"))
return source.Where(expr.Map(value => EF.Functions.Like(value, searchValue)));
else
return source.Where(expr.Map(value => value == searchValue));
}
static Expression<Func<TSource, TTarget>> Map<TSource, TIntermediate, TTarget>(this Expression<Func<TSource, TIntermediate>> source, Expression<Func<TIntermediate, TTarget>> target)
=> Expression.Lambda<Func<TSource, TTarget>>(Expression.Invoke(target, source.Body), source.Parameters);
}
主要方法是WhereMatch
。它使用称为Expression
的小型Map
帮助程序方法来构成其他Lambda表达式中的Lambda表达式。
示例用法为:
// SearchPerson searchPerson
// DbContext db
var query = db.Set<Person>()
.WhereMatch(p => p.Name, searchPerson.Name)
.WhereMatch(p => p.MothersName, searchPerson.MothersName)
.WhereMatch(p => p.FathersName, searchPerson.FathersName);
答案 1 :(得分:1)
对于平等比较,您应该使用==
:
EFPersonObject.Where(m => m.Name == searchPerson.Name);
对于LIKE
:
like 'something%'
:(StartsWith
方法)
EFPersonObject.Where(m => m.Name.StartsWith(searchPerson.Name));
like '%something'
:(EndsWith
方法)
EFPersonObject.Where(m => m.Name.EndsWith(searchPerson.Name));
like '%something%'
:(Contains
方法)
EFPersonObject.Where(m => m.Name.Contains(searchPerson.Name));