我的应用程序中有一个很好的干净域图层,以DDD方式开发。在开发域时,根本没有考虑数据库。属性名称有意义,不在所有大写中,并且与我的应用程序相关。
今天,我正在实现一个存储库来从现有的EF DbContext中提取。 DbContext的开发(基本上)与设计不佳的Oracle数据库相匹配。
理想情况下,我想实现这样的存储库:
public interface IRepository {
IQueryable<T> Find<T>(Expression<Func<T, bool>> query) where T : IMyDomainEntity;
}
T
是我的域名实体。但是,在我的存储库中的Find
方法中,我必须...
以某种方式将表达式转换为使用DbContext
我不知道该怎么做。
查询DbContext
表达式“映射”后,这很简单
以某种方式映射到我的域对象
我确信我可以使用AutoMapper或实现我自己的映射器。
返回尚未前往数据库的IQueryable。
在#1-3
完成所有干预后,不确定这是否可行
那么,过去这个问题是如何解决的?这里有可重复使用的模式吗?
答案 0 :(得分:0)
嗯,你已经走上了正确的轨道,只要实现你想说的话:)
1.您将表达式传递给find方法,只需在Where子句
中使用该表达式即可2.你只需要从你的DbContext中获取正确的DbSet来查询,DbContext有一个获取给定类型的DbContext的方法,使用它然后你可以查询
public IQueryable<T> Find<T>(Expression<Func<T, bool>> query) where T : IMyDomainEntity
{
var dbSet = context.Set<T>();
return dbSet.Where(query);
}
3.如果您的域对象不是EF映射到数据库的域对象,则需要根据DbContext类中的数据库中的内容自定义映射(不需要自动化),因此您可能需要你的DbContext类
中有类似的东西public class MyContext : DbContext
{
...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.Map(a => a.ToTable("DB_USERS"))
.Property(a => a.Email).HasColumnName("MAIL");
base.OnModelCreating(modelBuilder);
}
}
要从DB中的表DB_USERS映射到类User,具有不同的字段名称等,这里有一篇文章
http://www.codeproject.com/Articles/165720/Using-the-Code-First-Model-Configuration-Classes
如果您不想/不能更改DbContext类,也可以使用属性将属性映射到正确的表列
http://msdn.microsoft.com/en-us/data/gg193958
或者您可以拥有一组映射到您的数据库的不同实体,并使用automapper将它们转换为您的域对象,但您不会丢失。因为您需要实现查询以将其自动化到您的域模型,所以需要4个铃声。
4.不需要做任何特别的事,EF负责那个
更新:无法访问DbContext的解决方案(不是完全通用的版本,但有效)
这个想法是为每个域类创建存储库的映射部分,因此所有域都正确绑定。继续使用User
域模型和DBUser
表模型:
public class User : IDomainModelEntity
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
public class DBUser
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int USER_ID { get; set; }
[Required]
[MaxLength(150)]
public string USER_NAME { get; set; }
[Required]
[MaxLength(260)]
public string USER_MAIL { get; set; }
}
然后你会有一个抽象的存储库和每个域类的具体存储库,它实现了映射的基本GetAll查询:
public abstract class Repository<T> where T : IDomainModelEntity
{
protected readonly DbContext _context;
public Repository(DbContext context)
{
_context = context;
}
public abstract IQueryable<T> GetAll();
public IQueryable<T> Find(Expression<Func<T, bool>> predicate)
{
return GetAll().Where(predicate);
}
}
public class UserRepository : Repository<User>
{
public UserRepository(DbContext context)
: base(context)
{
}
public override IQueryable<User> GetAll()
{
return _context.Set<DBUser>()
.Select(u => new User
{
Id = u.USER_ID,
Name = u.USER_NAME,
Email = u.USER_MAIL
});
}
}
现在要使用它,你只需调用find或获取存储库中的所有内容......
using (var context = new CompanyDbContext())
{
var repo = new UserRepository(context);
var list = repo.Find(a=>a.Id >= 2).ToList();
list.ForEach(a => Console.WriteLine("Id: {0}, Name {1}, email {2}", a.Id, a.Name, a.Email));
}
它不是完全通用的,因为您需要为每个需要使用的域类传递存储库,但这可能是可接受的折衷方案
希望这有帮助