【发布时间】:2020-03-19 10:52:25
【问题描述】:
我正在尝试编写一个用于所有对象的通用搜索。 我有这段代码,它可以很好地搜索一个对象的属性,但我也想搜索相关对象的属性。
例如。我有这些模型/对象
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public string Address{ get; set; }
public ICollection<Contract> Contracts { get; set; }
}
public class Contract
{
public int Id { get; set; }
public DateTime From{ get; set; }
public DateTime To{ get; set; }
public string Comment{ get; set; }
public int CustomerId { get; set; }
[ForeignKey("CustomerId")]
public Customer Customer { get; set; }
}
我想搜索是否有任何属性包含一些字符串,例如。 “彼得”,我会这样称呼它:
string searchString = "Peter";
var customers = db.Customers
.Include(x => x.Contracts)
.WhereAnyPropertiesOfSimilarTypeContains(searchString);
此代码将检查“客户”的任何属性是否包含字符串“彼得”。 但我还需要检查相关模型“合同”是否包含“彼得。
public static class EntityHelper
{
public static IQueryable<TEntity> WhereAnyPropertiesOfSimilarTypeContains<TEntity, TProperty>(this IQueryable<TEntity> query, TProperty value)
{
var param = Expression.Parameter(typeof(TEntity));
var predicate = PredicateBuilder.False<TEntity>(); //--- True to equal
var entityFields = GetEntityFieldsToCompareTo<TEntity, TProperty>();
foreach (var fieldName in entityFields)
{
MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var predicateToAdd = Expression.Lambda<Func<TEntity, bool>>(
Expression.Call(
Expression.PropertyOrField(param, fieldName), method,
Expression.Constant(value)), param);
predicate = predicate.Or(predicateToAdd); //--- And to equal
}
return query.Where(predicate);
}
// TODO: You'll need to find out what fields are actually ones you would want to compare on.
// This might involve stripping out properties marked with [NotMapped] attributes, for
// for example.
public static IEnumerable<string> GetEntityFieldsToCompareTo<TEntity, TProperty>()
{
Type entityType = typeof(TEntity);
Type propertyType = typeof(TProperty);
var fields = entityType.GetFields()
.Where(f => f.FieldType == propertyType)
.Select(f => f.Name);
var properties = entityType.GetProperties()
.Where(p => p.PropertyType == propertyType)
.Select(p => p.Name);
return fields.Concat(properties);
}
}
谢谢。
【问题讨论】:
-
反射...是我在这里看到的唯一方式。
-
你能说得更具体点吗?
-
无限递归 - 是阻止我发布答案的原因。
-
分享你得到的。也许我会想出点什么。
-
有很多问题展示了如何递归地获取包括子对象在内的所有属性 - 我选择了一个作为重复项。如果那不是您要找的东西 - edit 需要澄清的问题。请注意,大多数答案都假设对象树而不是带有循环的图 - 确保也澄清这一点(同样简单地不访问同一对象两次通常就足够且易于检查)。此外,您还用“泛型”而不是“反射”标记了问题 - 澄清一下为什么您正在寻找基于泛型的解决方案也会很有用。