Проблема: Мы широко используем шаблон репозитория для упрощения операций чтения / записи в нашем хранилище данных (MS SQL с использованием LINQ) для нескольких приложений и подразделов функциональности.У нас есть ряд методов, которые делают что-то похожее друг на друга.
Например, у нас есть класс методов 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
}
);
}
Как вы можете сказать по коду, все они очень похожи, пока вы не посмотрите на сигнатуру, а затем не доберетесь до оператора return, где мы создаем экземпляры ClassErrorEntry и ClassTimerLogEntry.
Я хочу создать вспомогательный метод, который добавлю в базовый класс, от которого наследуются все репозитории.
Я хочу иметь возможность передавать аргументы, которые можно использовать для создания экземпляраобъекты и упаковать их в возвращаемый 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-го символа - (
, а тип, переданный в метод Validate, указывает позицию 4 или первую 'C'
.