一些背景知识:在我的应用程序中有多个层,其中两个是域层和基础架构层,它们充当我的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中使用的表达式。具体的示例如下:我有一个实现IRepository接口的通用DomainRepository (参见上文)。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是什么,这样我才能将域层中的谓词转换为实现IDao的DAL类中Where方法可以理解的内容:
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之后,我以为我已经做了一些事情了,但是它不允许我传入一个包含&&或||的compex linq表达式,或者比一个简单的i => i.id.Equals(12345)类型查询更复杂的任何内容。
我正在使用Automapper,所以任何使用它的解决方案都会很棒,但我现在对任何想法都持开放态度。我真的被卡住了,我已经研究了好几天了。这似乎是一项相当常见的任务:将基于类型的查询从体系结构中的一层转换为DAL中使用的类型。
提前感谢您的帮助。
发布于 2013-05-11 15:19:10
你可能不应该这样做,看起来你把事情搞得过于复杂了。
首先:如果您使用通用存储库模式,则基本上违反了TDA原则;您正在创建对存储实现的直接依赖。在您的通用存储库中使用"all“、"by Id”和"full text search“是很好的,但任何其他内容都应该被您的界面隐藏起来。一个简单的例子:
repo.search(x=>x.IsActive==true)让我们假设这是一个简单的标志,不知何故,后来你的域在某个地方发生了变化,你决定也可以软删除一个项目。这意味着您需要将域中所有位置的代码从以前的代码更改为以下代码:
repo.search(x=>x.IsActive==true && x.IsDeleted == false)要做到这一点,正确的方法应该是在您的存储库上使用一个适当的方法,如下所示
repo.ActiveItems()这可以确保你不会到处散布你的行为。
接下来,如果您要公开一个通用搜索,为什么不在您的域模型中直接使用Linq;毕竟,您仍然是在sql对象的另一层上实现一层。你能给我解释一下增加这些额外的层有什么价值吗?毕竟,它们仍然与相同的实现捆绑在一起(即使它们可能是一些额外的名称/值转换)。
https://stackoverflow.com/questions/14665837
复制相似问题