免責事項:サービス/エンティティ/などの名前をメモ帳のSOの一般的なものに変更しました。クラス名に関して矛盾が見られる場合は、問題ではないので無視してください。
クライアント用の WCF サービスに取り組んでおり、シリアライズしている式に問題があります。現在、Serialize.Linqを使用して式のシリアル化を処理しています。その上で、DataContract クラスを使用してクライアント側で式を作成し、それを Entity クラスを使用して式に変換しています。
次の 2 つのクラスを想定します。
- MyEntity (プロジェクトの DataContract 名前空間の一部)
- MyEntity (プロジェクトのエンティティ名前空間の一部)
どちらも同じプロパティを持ち、AutoMapper を使用して EF 経由で取得したエンティティを DataContract オブジェクトに変換し、そのオブジェクトをクライアントに送り返します。
式の変換に対処するために、ExpressionVisitor クラスを使用しています。
class MyExpressionVisitor : ExpressionVisitor
{
public ParameterExpression ParameterExpression { get; private set; }
public MyExpressionVisitor(ParameterExpression newParameterExp)
{
ParameterExpression = newParameterExp;
}
protected override Expression VisitParameter(ParameterExpression node)
{
return ParameterExpression;
}
protected override Expression VisitMember(MemberExpression node)
{
if (node.Member.DeclaringType == typeof(DataContracts.MyEntity))
{
return Expression
.MakeMemberAccess(this.Visit(node.Expression), typeof(Entities.MyEntity).GetMember(node.Member.Name).FirstOrDefault());
}
return base.VisitMember(node);
}
}
これは私が自分のサービスを呼び出す方法です:
Expression<Func<DataContracts.MyEntity, bool>> expression =
fl.SomeNameField1 == "John Doe" || fl.SomeNameField2 == "John Doe";
var entities = manager.MyService.GetFilteredEntities(expression.ToExpressionNode());
これは私の現在のサービス実装です(部分的、戻り行の省略など...)GetFilteredEntities
:
// Using Serialize.Linq for send expressions over WCF.
// query is an ExpressionNode from the Serialize.Linq library.
// This DOES NOT execute the where clause on the database.
var expression = query.ToExpression<Func<DataContracts.MyEntity, bool>>();
var visitor = new MyExpressionVisitor(Expression.Parameter(typeof(Entities.MyEntity), expression.Parameters[0].Name));
var entityExpression = Expression.Lambda<Func<Entities.MyEntity, bool>>(visitor.Visit(expression.Body), visitor.ParameterExpression);
var func = entityExpression.Compile();
var entities = this.Entities.MyEntities.Where(func);
このコードはすべて機能しますがWhere
、データベース レベルでは適用されず、テーブルのすべての行のメモリ内セットに対して適用されます。テーブルには 15 万行以上あるため、これには長い時間がかかります。
サービスで必要な場所をハードコーディングすると、データベース レベルで where 句が適用されます。
// This DOES execute the where clause on the database.
var temp1 = this.Entities.MyEntities.Where(fl => fl.SomeNameField1 == "John Doe" || fl.SomeNameField2 == "John Doe");
// This DOES execute the where clause on the database.
Func<Entities.MyEntity, bool> func2 = fl => fl.SomeNameField1 == "John Doe" || fl.SomeNameField2 == "John Doe";
var temp2 = this.Entities.MyEntities.Where(func2);
ユーザーが名前、IDなどを渡してフィルタリングできるようにする一連のさまざまなサービス操作を作成できることはわかっていますが、このテーブルには途方もない量の列(200以上)があり、上記のデータベースにはゼロの入力があります. 私が書いているクライアントを使用している可能性のある他の開発者にとって、好きなデータと列を使用して式を作成できるようにする方がはるかに簡単なので、db レベルで where を適用してこれを取得したいと思います。
この投稿に関連するすべてを含めたことはほぼ確実です。SQL Server プロファイラーを使用して、EF が実行していたクエリを確認しました。これにより、どのクエリがどこで使用されたかがわかります。詳細については、必要に応じてお問い合わせください。
ありがとう!
/walloftext