尝试在业务域和数据域之间转换表达式树是否可行?

发布于 2024-09-16 19:21:20 字数 2688 浏览 7 评论 0原文

我有一个处理 LINQ to SQL 自动生成实体的存储库层。这些最终被映射到表面上的领域友好类型。我现在想为客户端代码提供一些更复杂的查询功能,并且客户端代码只知道域对象类型。

我想使用查询对象模式(如 Martin Fowler 的企业应用程序架构模式中所命名)来实现此功能,但允许客户端代码使用具有域类型的 lambda 表达式。在幕后,我想将域感知 lambda 表达式转换为数据库感知 lambda 并将此转换后的表达式发送到存储库,以便使用 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 映射来相互转换 DomainTypeDataEntityType 或者我会需要将 Query 显式映射到 Query

我最终希望这样做是为了能够灵活地使用任意映射函数,这些函数不一定是简单的对象属性。

I have a repository layer that deals with LINQ to SQL autogenerated entities. These eventually get mapped into domain-friendly types on the surface. I'd now like to provide some more sophisticated querying capabilities for the client code, and that client code knows only about the domain object types.

I'd like to implement this with the Query Object pattern (as named in Martin Fowler's Patterns of Enterprise Application Architecture), but allowing the client code to use lambda expressions with domain types. Under the covers, I'd like to convert the domain-aware lambda expression into a database-aware lambda and send this converted expression to the repository for execution against the database with LINQ to SQL.

I currently have a poor-man's implementation that restricts the client's mapping ability to simple properties, but I'd like to open it up a little to more sophisticated querying. I'm not sure how I would approach this with AutoMapper or any other existing mapping tool, nor am I sure OTTOMH how I could do it with homegrown code.

Here's the kind of functionality I'd like:

// 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) { ... }
}   

With the ultimate goal of getting something like this to work:

// 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));

My questions are really this, I think:

  1. Is it feasible to create such a mapper, and if so...
  2. Is it feasible to do so with a tool like AutoMapper, and if so...
  3. Is it possible to take advantage of the AutoMapper mapping that I already have that interconverts DomainType and DataEntityType or would I need to explicitly map Query<DomainType> to Query<DataEntityType>?

I ultimately want to do this to have the flexibility of using arbitrary mapping functions that are not necessarily simple object properties.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

似最初 2024-09-23 19:21:20

恕我直言,这个设计看起来相当复杂。您是否研究过直接通过 ORM 定义域类型的可能性?毕竟,这就是 ORM 的设计目的...它肯定会带来很多可能性,而无需付出巨大的额外努力...

许多人不知道 Linq 2 SQL 实际上支持 POCO 风格,至少在某种程度上?如果您可以考虑其他 ORM 替代方案,NHibernate 和 Entity Framework 都有更好的 POCO 支持。

POCO 允许您直接在 ORM 之上定义域模型,但在某种程度上,您的域类可能(或多或少,取决于实际的 ORM)“持久性无知”。因此,您可以利用 ORM 的查询功能向用户公开丰富的域查询 API。

如果您考虑实体框架 (v4),您可能还需要查看 WCF 数据服务

只需我的 2 美分...

IMHO, this design looks pretty complex. Have you investigated the possibility of defining your domain types directly through the ORM? It's what an ORM is designed for, after all... It would certainly open lot's of possibilities without this huge extra effort...

Many people don't know that Linq 2 SQL actually supports POCO style, at least to some extent? If you can consider other ORM alternatives, both NHibernate and Entity Framework have better POCO support though.

POCO allows you to define your domain model directly on top of the ORM, but in a way that your domain classes can be (more or less, depending on the actual ORM) 'persistence ignorant'. As such, you can leverage the ORM's querying capabilities to expose a rich domain querying API to your users.

If you would consider Entity Framework (v4), you might also want to have a look at WCF Data Services

Just my 2 cents...

温柔戏命师 2024-09-23 19:21:20

如果您打算允许针对 ViewModel 编写 LINQ 查询并在使用实体模型的存储库中执行它们,您还需要检查 LINQ 表达式树和表达式树转换。 AutoMapper 在翻译对象时会很有帮助,但是您的表达式树也需要翻译。

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

If you are going to allow LINQ queries written against ViewModels and execute them in the repository which uses entity models, you also need to checkout LINQ expression trees and expression tree translation. AutoMapper would be of help when translating the objects, but your expression trees would need translation too.

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文