問題:リポジトリパターンを広範囲に使用して、複数のアプリケーションと機能のサブセクションにわたるデータストア(LINQを使用するMS SQL)での読み取り/書き込み操作を容易にします。私たちは、すべてが互いに似たようなことをする一連の方法を持っています。
たとえば、ProcessAndSortXXXXXクラスのメソッドがあります。
private static IEnumerable<ClassErrorEntry> ProcessAndSortClassErrorLog(IQueryable<ClassErrorDb> queryable, string sortOrder)
{
var dynamic = queryable;
if (!String.IsNullOrEmpty(sortOrder.Trim()))
{
dynamic = dynamic.OrderBy(sortOrder);
}
return dynamic
.Select(l =>
new ClassErrorEntry(l.Id)
{
ClassId = l.ClassId,
Code = l.Code,
Message = l.Message,
Severity = l.Severity,
Target = l.Target
}
);
}
...と...
private static IEnumerable<ClassTimerLogEntry> ProcessAndSortClassTimerLog(IQueryable<ClassTimerDb> queryable, string sortOrder)
{
var dynamic = queryable;
if (!String.IsNullOrEmpty(sortOrder.Trim()))
{
dynamic = dynamic.OrderBy(sortOrder);
}
return dynamic
.Select(l =>
new ClassTimerLogEntry(l.Id)
{
ClassName = l.ClassName,
MethodName = l.MethodName,
StartTime = l.StartTime,
EndTime = l.EndTime,
ParentId = l.ParentId,
ExecutionOrder = l.ExecutionOrder
}
);
}
コードからわかるように、署名を確認してから、ClassErrorEntryとClassTimerLogEntryのインスタンスを構築しているreturnステートメントに到達するまで、これらはすべて非常に似ています。
すべてのリポジトリが継承する基本クラスに追加するユーティリティメソッドを作成したいと思います。
オブジェクトをインスタンス化し、それらを返すIEnumerableにパックするために使用できる引数を渡せるようにしたいと思います。
私はScottGuによるこの投稿を見つけました、そしてそれは私が必要とするもののほとんどを私に与えます。これは次のようになります(ドキュメントのサンプルから):
var query =
db.Customers.
Where("City = @0 and Orders.Count >= @1", "London", 10).
OrderBy("CompanyName").
Select("new(CompanyName as Name, Phone)");
しかし、ここで私は行き詰まります。動的クエリを構築できるように、LINQテーブルとDataContextを一般的な方法で渡す方法についてのポインターまたは提案が必要です。
疑似コードで署名をモックアップすると、次のようになります。
protected internal IEnumerable ProcessAndSort(IQueryable source, string selectClause, string whereClause, string orderByClause);
これを理解すると、完成した署名が異なって見える可能性があることに気付きました。
ありがとうございました!
アップデート!
これで、匿名型を生成するように機能するコードがありますが、具象型に変換すると失敗します。
public static IEnumerable<TResult> ProcessAndSort<T, TResult>(IQueryable<T> queryable,
string selector, Expression<Func<T, bool>> predicate, string sortOrder)
{
var dynamic = queryable.Where(predicate).AsQueryable();
if (!String.IsNullOrEmpty(sortOrder.Trim()))
{
dynamic = dynamic.OrderBy(sortOrder);
}
var result= dynamic.Select(selector).Cast<TResult>();
return result;
}
このメソッドを呼び出すコードは次のとおりです。
[TestMethod]
public void TestAnonymousClass()
{
var loggingContext = new LoggingDbDataContext(DatabaseConnectionString);
var repo = new LoggingRepository(loggingContext);
var result = repo.TestGetClassErrorLog(4407, 10, 0,
"new ( ClassId as ClassId, " +
"Code as Code, " +
"Message as Message, " +
"Severity as Severity, " +
"Target as Target )", "Target");
TestContext.WriteLine(result.ToList().Count.ToString());
}
最後の行TestContext.WriteLine(result.ToList().Count.ToString());
は例外をスローしますSystem.InvalidOperationException: No coercion operator is defined between types 'DynamicClass1' and 'Utilities.Logging.ClassErrorEntry'.
ただし、このコードのチャンクは失敗します。
[TestMethod]
public void TestNamedClass()
{
var loggingContext = new LoggingDbDataContext(DatabaseConnectionString);
var repo = new LoggingRepository(loggingContext);
var result = repo.TestGetClassErrorLog(4407, 10, 0,
"new ClassErrorEntry(Id) { ClassId = ClassId, " +
"Code = Code, " +
"Message = Message, " +
"Severity = Severity, " +
"Target = Target }", "Target");
TestContext.WriteLine(result.ToList().Count.ToString());
}
これは解析エラーで失敗します。Test method eModal.Repositories.Test.RepositoryBaseTest.TestConcreteClass threw exception:
System.Linq.Dynamic.ParseException: '(' expected, found 'ClassErrorEntry' ('Identifier') at char 19 in 'new ClassErrorEntry(Id) { ChassisAuthId = ChassisAuthId, Code = Code, Message = Message, Severity = Severity, Target = Target }'
19番目の文字位置がa(
であり、Validateメソッドに渡されたタイプが4の位置、つまり最初のを示しているため、文字位置が疑わしいかどうかはわかりません'C'
。