c# Repository pattern 和 where lambdas,如何转换类型
c# Repository pattern and where lambdas, how to convert type
我正在尝试构建一个 Entity framework 带有数据传输对象和独立数据提供者的抽象存储库。我们需要能够根据安装在 oracle、sql 服务器和 azure sql 之间切换。
最终存储库returns DTO 到消费代码。获取、更新和删除工作正常。我遇到的问题是 where 子句等的 lambda。通用存储库不知道来自数据提供者的实际实体对象,因此我无法创建 where lambda。
P.S。使用AutoMapper在Entity和DTO之间进行转换
//Repository base
public class Repository<TEntity> : IDisposable, IRepository<TEntity> where TEntity : class, IEntity
{
public virtual IList<TEntity> GetList(Func<TEntity, bool> where, params Expression<Func<TEntity, object>>[] navigationProperties)
{
List<TEntity> list;
IQueryable<TEntity> dbQuery = Context.Set<TEntity>();
//Apply eager loading
foreach (Expression<Func<TEntity, object>> navigationProperty in navigationProperties)
dbQuery = dbQuery.Include<TEntity, object>(navigationProperty);
list = dbQuery
.AsNoTracking()
.Where(where)
.ToList<TEntity>();
return list;
}
}
//Implementing repository where T is the entity from the EF model
public class UserRepository<T> : IUserRepository, IUnitOfWork
where T : class, IEntity
{
public Repository<T> Base { get; private set; }
public UserRepository(DbContext context)
{
Base = new Repository<T>(context);
}
public List<UserAccountDTO> GetList(Expression<Func<UserAccountDTO, bool>> where)
{
T obj = SupportedRepos.DTOMapper.Map<T>(where.Parameters[0]);
/* HOW CAN I CONVERT THE FUNC<>? */
//Base.GetList();
return null;
}
}
public void TestMethod1()
{
var dbtypeFromConfig = RepoEF.Setup.StorageType.SQLServer;
using (var repo = RepoEF.Setup.SupportedRepos.Create(dbtypeFromConfig))
{
//WORKS FINE, CHANGES AND UPDATES
var source = repo.Get(3);
source.LookupId = 111111;
repo.Add(source);
//CAN'T CREATE WHERE BECAUSE UserRepository<T> ONLY SEES IEntity
repo.GetList(x => x.UserAccountId == 3);
}
}
是否可以构建一个 Func<> 以传递给基础存储库。
如果没有任何想法,我该如何更改设计来实现我的需要?
也许我可以深入研究您当前的存储库模式实现并尝试修复它,但我相信毕竟有许多设计缺陷会迫使您完全重构您的解决方案。
所以我会给你一些提示:
1) 存储库仍然是 域,因此它始终与 域对象
一起使用
域不应与 DTO 一起使用。当您想要在逻辑或物理边界之间传输数据时,您可以使用 DTO 模式。例如,当域服务需要向应用程序服务提供一些域对象的列表时。该列表将作为域对象列表的 DTO 公开。
2)数据库技术开关是数据映射层的职责(即Entity Framework)。
您的存储库应该与数据库技术保持无关,并与 OR/M 框架相结合。
3) 如果一个用户仓库是一个仓库,你应该使用继承而不是组合
因此,UserRepository
应该既实现 IUserRepository
又派生自 Repository<User>
。
4) 具体的存储库不应接受泛型类型参数来提供要处理的域对象
归根结底,像 IUserRepository
这样的具体存储库处理 User
的实例,因此,您为什么需要 TEntity
通用参数?由于您有这个设计缺陷,TEntity
不是 T
...这就是您要解决的问题背后的原因...
我正在尝试构建一个 Entity framework 带有数据传输对象和独立数据提供者的抽象存储库。我们需要能够根据安装在 oracle、sql 服务器和 azure sql 之间切换。
最终存储库returns DTO 到消费代码。获取、更新和删除工作正常。我遇到的问题是 where 子句等的 lambda。通用存储库不知道来自数据提供者的实际实体对象,因此我无法创建 where lambda。
P.S。使用AutoMapper在Entity和DTO之间进行转换
//Repository base
public class Repository<TEntity> : IDisposable, IRepository<TEntity> where TEntity : class, IEntity
{
public virtual IList<TEntity> GetList(Func<TEntity, bool> where, params Expression<Func<TEntity, object>>[] navigationProperties)
{
List<TEntity> list;
IQueryable<TEntity> dbQuery = Context.Set<TEntity>();
//Apply eager loading
foreach (Expression<Func<TEntity, object>> navigationProperty in navigationProperties)
dbQuery = dbQuery.Include<TEntity, object>(navigationProperty);
list = dbQuery
.AsNoTracking()
.Where(where)
.ToList<TEntity>();
return list;
}
}
//Implementing repository where T is the entity from the EF model
public class UserRepository<T> : IUserRepository, IUnitOfWork
where T : class, IEntity
{
public Repository<T> Base { get; private set; }
public UserRepository(DbContext context)
{
Base = new Repository<T>(context);
}
public List<UserAccountDTO> GetList(Expression<Func<UserAccountDTO, bool>> where)
{
T obj = SupportedRepos.DTOMapper.Map<T>(where.Parameters[0]);
/* HOW CAN I CONVERT THE FUNC<>? */
//Base.GetList();
return null;
}
}
public void TestMethod1()
{
var dbtypeFromConfig = RepoEF.Setup.StorageType.SQLServer;
using (var repo = RepoEF.Setup.SupportedRepos.Create(dbtypeFromConfig))
{
//WORKS FINE, CHANGES AND UPDATES
var source = repo.Get(3);
source.LookupId = 111111;
repo.Add(source);
//CAN'T CREATE WHERE BECAUSE UserRepository<T> ONLY SEES IEntity
repo.GetList(x => x.UserAccountId == 3);
}
}
是否可以构建一个 Func<> 以传递给基础存储库。
如果没有任何想法,我该如何更改设计来实现我的需要?
也许我可以深入研究您当前的存储库模式实现并尝试修复它,但我相信毕竟有许多设计缺陷会迫使您完全重构您的解决方案。
所以我会给你一些提示:
1) 存储库仍然是 域,因此它始终与 域对象
一起使用域不应与 DTO 一起使用。当您想要在逻辑或物理边界之间传输数据时,您可以使用 DTO 模式。例如,当域服务需要向应用程序服务提供一些域对象的列表时。该列表将作为域对象列表的 DTO 公开。
2)数据库技术开关是数据映射层的职责(即Entity Framework)。
您的存储库应该与数据库技术保持无关,并与 OR/M 框架相结合。
3) 如果一个用户仓库是一个仓库,你应该使用继承而不是组合
因此,UserRepository
应该既实现 IUserRepository
又派生自 Repository<User>
。
4) 具体的存储库不应接受泛型类型参数来提供要处理的域对象
归根结底,像 IUserRepository
这样的具体存储库处理 User
的实例,因此,您为什么需要 TEntity
通用参数?由于您有这个设计缺陷,TEntity
不是 T
...这就是您要解决的问题背后的原因...