一些背景:我的应用程序中有多个层,其中两个是域层和一个用作我的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 接口(见上文)。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 在选择器类型之间
但这只告诉我如何在谓词到Func<DTOType,bool>
(谓词)之间转换Func<DomainType,bool>
而不是表达式到表达式。我正在寻找一种转换这样的东西的方法:
Expression<Func<TDomainEntity, bool>> predicate
对此:
Expression<Func<TDAOEntity, bool>> predicate
在我找到这篇关于多表达式树的文章后,我以为我正在做一些事情,但它不允许我传入包含 &&或 || 或任何比简单的 i => i.id.Equals(12345) 类型查询更复杂的 compex linq 表达式。
我正在使用自动映射器,所以任何使用它的解决方案都会很棒,但我现在对任何想法都持开放态度。我真的被困住了,已经研究了好几天了。这似乎是一个相当常见的任务:将基于类型的查询从体系结构中的一个层转换为 DAL 中使用的类型。
提前感谢您的帮助。
你可能不应该这样做,看起来你把事情复杂化了。
首先:如果您使用通用存储库模式,则基本上违反了TDA原则;您正在创建对存储实现的直接依赖关系。在您的通用存储库上有一个"all","by Id"和"全文搜索"是可以的,但任何其他内容都应该被您的界面隐藏。一个简单的例子:
repo.search(x=>x.IsActive==true)
假设这是一个简单的标志,后来你的域在某处发生了变化,你决定也可以软删除一个项目。这意味着您需要将域中所有位置的代码从前者更改为以下内容:
repo.search(x=>x.IsActive==true && x.IsDeleted == false)
执行此操作的正确方法是在您的存储库中使用这样的正确方法
repo.ActiveItems()
这样可以确保您不会将您的行为传播到任何地方。
接下来,如果要公开泛型搜索,为什么不直接在域模型中使用 Linq;毕竟,您仍在 SQL 对象的另一层上实现一层。你能解释一下添加这些额外层的附加值吗?毕竟,它们仍然绑定到相同的实现(即使它们可能是一些额外的名称/值转换)。