0

私のデータモデルには、共通の親を持ついくつかのテーブルがあります。私はEntityFrameworkを使用していて、子オブジェクトから親に戻るナビゲーションプロパティを持っていますが、その逆はありません。この理由は、この共通の親の何百人もの子供がいるからです。例として、すべてのレポートのwhere基準は同じになります。

 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。可能であれば、このwhereセクションを次のような独自の関数に分離したいと思います。

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式は親ではなく子タイプで入力されるため、これは機能しません。これを達成する方法について何か考えはありますか?

ありがとう!

4

1 に答える 1

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));
于 2012-11-05T20:52:19.800 に答える