我的数据模型有许多具有共同父级的表。我正在使用实体框架并从子对象返回到父对象的导航属性,而不是其他方式。原因是这个共同父母将有100个孩子。每个报告的标准都是相同的,例如:
crudEngine.Read<ChildEntity>()
.Include(parameters => parameters.ParentEntity)
.Where(parameter => parameter.ParentEntity.LastUser.Contains(searchText) ||
(isInt && SqlFunctions.DatePart("year", parameter.ParentEntity.CreationDate) == intSearchText) ||
(isInt && SqlFunctions.DatePart("month", parameter.ParentEntity.CreationDate) == intSearchText) ||
(isInt && SqlFunctions.DatePart("day", parameter.ParentEntity.CreationDate) == intSearchText) ||
(isDate && SqlFunctions.DateAdd("dy", SqlFunctions.DateDiff("dy", "1900-01-01", parameter.ParentEntity.CreationDate), "1900-01-01") == dateSearchText) ||
(isInt && SqlFunctions.DatePart("year", parameter.ParentEntity.LastModifiedDate) == intSearchText) ||
(isInt && SqlFunctions.DatePart("month", parameter.ParentEntity.LastModifiedDate) == intSearchText) ||
(isInt && SqlFunctions.DatePart("day", parameter.ParentEntity.LastModifiedDate) == intSearchText) ||
(isDate && SqlFunctions.DateAdd("dy", SqlFunctions.DateDiff("dy", "1900-01-01", parameter.ParentEntity.LastModifiedDate), "1900-01-01") == dateSearchText) ||
parameter.ParentEntity.CreationUser.Contains(searchText) ||
parameter.ParentEntity.Description.Contains(searchText)...
这个标准将用于引用ParentEntity
的每个子实体。如果可能的话,我想以某种方式将这个部分分成它自己的函数,如下所示:
private Predicate<ParentEntity> GetParentWhere(string searchText)
{
int intSearchText;
bool isInt = int.TryParse(searchText, out intSearchText);
DateTime dateSearchText;
bool isDate = DateTime.TryParse(searchText, out dateSearchText);
SubmissionStatus submissionStatus;
bool isStatus = Enum.TryParse(searchText, true, out submissionStatus);
return parent =>
(isInt && SqlFunctions.DatePart("year", parent.CreationDate) == intSearchText) ||
(isInt && SqlFunctions.DatePart("month", parent.CreationDate) == intSearchText) ||
(isInt && SqlFunctions.DatePart("day", parent.CreationDate) == intSearchText) ||
(isDate && SqlFunctions.DateAdd("dy", SqlFunctions.DateDiff("dy", "1900-01-01", parent.CreationDate), "1900-01-01") == dateSearchText) ||
(isInt && SqlFunctions.DatePart("year", parent.LastModifiedDate) == intSearchText) ||
(isInt && SqlFunctions.DatePart("month", parent.LastModifiedDate) == intSearchText) ||
(isInt && SqlFunctions.DatePart("day", parent.LastModifiedDate) == intSearchText) ||
(isDate && SqlFunctions.DateAdd("dy", SqlFunctions.DateDiff("dy", "1900-01-01", parent.LastModifiedDate), "1900-01-01") == dateSearchText) ||
parent.CreationUser.Contains(searchText) ||
parent.Description.Contains(searchText) ||
parent.LastUser.Contains(searchText) ||
(isStatus && parent.Status == (int) submissionStatus);
}
然后从我的代码中调用它,如下所示:
return crudEngine.Read<ChildEntity>().Include(parameters => parameters.ParentEntity)
.Where(GetParentWhere(searchText));
但这不起作用,因为Where表达式是使用子类型而不是父类型键入的。有关如何实现这一点的任何想法?
谢谢!
答案 0 :(得分:2)
最简单的选择是让您的子实体实现一个公开ParentEntity
属性的接口:
public interface IHaveParentEntity
{
ParentEntity ParentEntity { get; }
}
private Expression<Func<TChildEntity, bool>> GetParentWhere<TChildEntity>(string searchText)
where TChildEntity : IHaveParentEntity
{
int intSearchText;
bool isInt = int.TryParse(searchText, out intSearchText);
DateTime dateSearchText;
bool isDate = DateTime.TryParse(searchText, out dateSearchText);
SubmissionStatus submissionStatus;
bool isStatus = Enum.TryParse(searchText, true, out submissionStatus);
return child =>
child.ParentEntity.CreationUser.Contains(searchText) ||
...
;
}
...
return crudEngine.Read<ChildEntity>()
.Include(parameters => parameters.ParentEntity)
.Where(GetParentWhere<ChildEntity>(searchText));
如果您无法修改子实体,则可能需要查看构建表达式树。由于查询的复杂性,使用表达式重写可能更容易,而不是手工构建整个表达式:
private Expression<Func<TChildEntity, bool>> GetParentWhere<TChildEntity>(
Expression<Func<TChildEntity, ParentEntity>> parentSelector,
string searchText)
{
int intSearchText;
bool isInt = int.TryParse(searchText, out intSearchText);
DateTime dateSearchText;
bool isDate = DateTime.TryParse(searchText, out dateSearchText);
SubmissionStatus submissionStatus;
bool isStatus = Enum.TryParse(searchText, true, out submissionStatus);
Expression<Func<ParentEntity, bool>> predicate = parent =>
parent.CreationUser.Contains(searchText) ||
...
;
Expression body = ReplacementVisitor.Replace(
predicate,
predicate.Parameters[0],
parentSelector.Body);
return Expression.Lambda<Func<TChildEntity, bool>>(body,
parentSelector.Parameters[0]);
}
private sealed class ReplacementVisitor : ExpressionVisitor
{
private IList<ParameterExpression> SourceParameters { get; set; }
private Expression ToFind { get; set; }
private Expression ToReplace { get; set; }
public static Expression Replace(
LambdaExpression source,
Expression toFind,
Expression toReplace)
{
var visitor = new ReplacementVisitor
{
SourceParameters = source.Parameters,
ToFind = toFind,
ToReplace = toReplace,
};
return visitor.Visit(source.Body);
}
private Expression ReplaceNode(Expression node)
{
return (node == ToFind) ? ToReplace : node;
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (SourceParameters.Contains(node)) return ReplaceNode(node);
return SourceParameters.FirstOrDefault(p => p.Name == node.Name) ?? node;
}
}
...
return crudEngine.Read<ChildEntity>()
.Include(parameters => parameters.ParentEntity)
.Where(GetParentWhere<ChildEntity>(child => child.ParentEntity, searchText));