Возможно ли попытаться преобразовать деревья выражений между бизнес-областями и областями данных?

У меня есть уровень репозитория, который имеет дело с автоматически сгенерированными объектами LINQ to SQL. В конечном итоге они преобразуются в удобные для домена типы на поверхности. Теперь я хотел бы предоставить более сложные возможности запросов для клиентского кода, и этот клиентский код знает только о типах объектов предметной области.

Я хотел бы реализовать это с помощью шаблона Query Object (как он назван в «Шаблонах архитектуры корпоративных приложений» Мартина Фаулера), но позволяя клиентскому коду использовать лямбда-выражения с типами домена. Под прикрытием я хотел бы преобразовать лямбда-выражение с поддержкой домена в лямбда-выражение с поддержкой базы данных и отправить это преобразованное выражение в репозиторий для выполнения в базе данных с помощью LINQ to SQL.

В настоящее время у меня есть реализация бедняка, которая ограничивает способность клиента отображать простые свойства, но я хотел бы немного открыть ее для более сложных запросов. Я не уверен, как бы я подошел к этому с помощью AutoMapper или любого другого существующего картографического инструмента, и я не уверен, как я могу сделать это с помощью собственного кода.

Вот какой функционал мне нужен:

// Example types to be interconverted...
//    DomainId should map to DataEntityId and vice versa
//    DomainName should map to DataEntityName and vice versa
public class DomainType
{
    public int DomainId { get; set; }
    public string DomainName { get; set; }
}
public class DataEntityType
{
    public int DataEntityId { get; set; }
    public string DataEntityName { get; set; }
}

// And this basic framework for a query object.
public class Query<T>
{
    public Query(Func<T, bool> expression) { ... }
    public Func<T, bool> Query { get; }
}

// And a mapper with knowledge about the interconverted query types
public class QueryMapper<TSource, TDestination> 
{
    public void SupplySomeMappingInstructions(
             Func<TSource, object> source, Func<TDestination, object> dest);
    public Query<TDestination> Map(Query<TSource> query);
}

// And a repository that receives query objects
public class Repository<T> 
{
    public IQueryable<T> GetForQuery(Query<T> query) { ... }
}   

С конечной целью заставить что-то вроде этого работать:

// a repository that is tied to the LINQ-to-SQL types.
var repository = new Repository<DataEntityType>(...);

// a query object that describes which domain objects it wants to retrieve
var domain_query = new Query<DomainType>(item => item.DomainId == 1);

// some mapping component that knows how to interconvert query types
var query_mapper = new QueryMapper<DomainType, DataEntityType>();
query_mapper.SupplySomeMappingInstructions(
                   domain => domain.DomainId, data => data.DataEntityId);
query_mapper.SupplySomeMappingInstructions(
                   domain => domain.DomainName, data => data.DataEntityName);


IQueryable<DataEntityType> results = 
    repository.GetForQuery(query_mapper.Map(domain_query));

Мои вопросы на самом деле таковы, я думаю:

  1. Возможно ли создать такой маппер, и если да...
  2. Возможно ли это сделать с помощью такого инструмента, как AutoMapper, и если да...
  3. Можно ли воспользоваться преимуществами сопоставления AutoMapper, которое у меня уже есть, которое взаимопреобразовывает DomainType и DataEntityType, или мне нужно явно сопоставить Query<DomainType> с Query<DataEntityType>?

В конечном итоге я хочу сделать это, чтобы иметь возможность использовать произвольные функции отображения, которые не обязательно являются простыми свойствами объекта.


person Chris Farmer    schedule 26.08.2010    source источник
comment
См. мой ответ на аналогичный вопрос здесь с использованием AutoMapper и ExpressionVisitor: функции между типами селекторов"> stackoverflow.com/questions/7424501/   -  person luksan    schedule 31.03.2013


Ответы (2)


ИМХО, эта конструкция выглядит довольно сложной. Вы исследовали возможность определения типов ваших доменов непосредственно через ORM? В конце концов, это то, для чего предназначен ORM... Это, безусловно, открыло бы множество возможностей без этих огромных дополнительных усилий...

Многие люди не знают, что Linq 2 SQL на самом деле поддерживает стиль POCO, по крайней мере, до некоторой степени? Если вы можете рассмотреть другие альтернативы ORM, то и NHibernate, и Entity Framework имеют лучшую поддержку POCO.

POCO позволяет вам определить вашу модель домена непосредственно поверх ORM, но таким образом, что ваши классы домена могут быть (более или менее, в зависимости от фактического ORM) «неосведомленными о сохранении». Таким образом, вы можете использовать возможности запросов ORM, чтобы предоставить своим пользователям богатый API запросов домена.

Если вы рассматриваете Entity Framework (v4), вы также можете взглянуть на Службы данных WCF

Просто мои 2 цента...

person jeroenh    schedule 28.08.2010

Если вы собираетесь разрешать запросы LINQ, написанные для ViewModels, и выполнять их в репозитории, который использует модели сущностей, вам также необходимо проверить деревья выражений LINQ и перевод деревьев выражений. AutoMapper может помочь при переводе объектов, но ваши деревья выражений также нуждаются в переводе.

http://blogs.msdn.com/b/charlie/archive/2008/01/31/expression-tree-basics.aspx

person kerem    schedule 28.12.2012