如何将Expression <func <domaintype>&gt;谓词转换为Expression <func <dtotype>谓词</func <dtotype> </func <domaintype>

时间:2013-02-02 19:53:29

标签: linq entity-framework domain-driven-design automapper expression-trees

一些背景知识:我在我的应用程序中有多个层,其中两个是域层,而基础架构层用作我的DAL。在域层中,我实现了一个通用的存储库模式:

    public interface IRepository<T, in TId> where T : IEntity<TId>
    {
        void Insert(T entity);
        void Delete(T entity);
        IQueryable<T> SearchFor(Expression<Func<T, bool>> predicate);
        IQueryable<T> GetAll();
        T GetById(TId id);
    }

在我的DAL中,我有一个通用的DAO模式:

    public interface IDao<TEntity> where TEntity : class
    {
        IQueryable<TEntity> Select();
        IQueryable<TEntity> GetAll();
        IQueryable<TEntity> Where(Expression<Func<TEntity, bool>> predicate);
        TEntity GetSingle(Expression<Func<TEntity, bool>> predicate);
        TEntity GetFirst(Expression<Func<TEntity, bool>> predicate);
        void Add(TEntity entity);
        void Delete(TEntity entity);
        void Attach(TEntity entity);
    }

我有一个域类,以商业术语表示个人。我的DAL层中有一个类似的单个对象,用于表示我的数据库中的对象。我有一个名为EntityFrameworkDao的类,它实现了我的IDAO接口,并负责在该DAO接口中找到的所有操作(CRUD和上述一些其他操作)。

我正在尝试(尝试几天)找到一种方法将存储库中使用的表达式映射到DAL中使用的表达式。具体的例子是:我有一个通用的DomainRepository,它实现了我的IRepository接口(见上文)。 SearchFor方法如下所示:

        public IQueryable<TDomainEntity> SearchFor(Expression<Func<TDomainEntity, bool>> predicate)
    {
        var convertedExpression = **SomeMagicFunctionToConvertExpressions**();
        var dataEntities = _dao.Where(convertedExpression);
        return AutoMapper.Mapper.Map<IEnumerable<TEfEntity>, IEnumerable<TDomainEntity>>(dataEntities).AsQueryable();
    }

我需要弄清楚SomeMagicFunctionToConvertExpressions是什么,以便我可以将我的域层中的谓词转换为Where方法可以在我的实现IDao的DAL类中理解的东西:

        public IQueryable<TEfEntity> Where(Expression<Func<TEfEntity, bool>> predicate)
        {
            return _context.Set<TEfEntity>().Where(predicate).AsQueryable();
        }

我尝试过使用本文中的Automapper的CreateMapExpression:AutoMapper for Func's between selector types

但这只会告诉我如何将Func<DomainType,bool>谓词转换为Func<DTOType,bool>(谓词),而不是表达式转换为表达式。我正在寻找一种方法来转换这样的东西:

Expression<Func<TDomainEntity, bool>> predicate

对此:

Expression<Func<TDAOEntity, bool>> predicate

在我发现this article关于破坏表达树之后,我以为我正在做些什么,但是它不允许我传递包含&amp;&amp;的compex linq表达式。或||或者比简单的i =>更复杂。 i.id.Equals(12345)类型查询。

我正在使用Automapper,所以使用它的任何solutoins都会很棒,但我现在对任何想法持开放态度。我真的很困难,现在已经研究了好几天了。这似乎是一项相当常见的任务:将基于类型的查询从架构中的一个层转换为DAL中使用的类型。

提前感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

你可能不应该这样做,看起来你的事情过于复杂。

首先:如果您使用通用存储库模式,则基本上违反了TDA原则;您正在创建与存储实现的直接依赖关系。在您的通用存储库上有一个“全部”,“通过Id”和“全文搜索”是很好的,但任何其他应该被您的界面隐藏。一个简单的例子:

repo.search(x=>x.IsActive==true)

我们假设这是一个简单的标志,稍后您的域名会在某个地方发生变化,并且您决定也可以对项目进行软删除。这意味着您需要将域中的代码从前者更改为此代码:

repo.search(x=>x.IsActive==true && x.IsDeleted == false)

执行此操作的正确方法是在您的存储库中使用适当的方法,例如

repo.ActiveItems()

这可以确保您不会在任何地方传播您的行为。

接下来,如果您要公开通用搜索,为什么不直接在您的域模型中使用Linq;毕竟,您仍然在另一层sql对象上实现一个层。你能解释一下添加这些额外层的附加价值吗?毕竟,它们仍然依赖于相同的实现(即使它们可能是一些额外的名称/值转换)。