aLets有一个简单的场景:
public interface IMember
{
string Name { get; set; }
}
public class MemberEF6Impl : IMember
{
//some annotations...
public string Name { get; set; }
}
public class MemberVMImpl : IMember
{
//some other annotations...
public string Name { get; set; }
//some functionality...
}
我的程序中有两个具体的接口实现。一种特别适用于数据库迁移的实现,一种用于我们的viewmodel。现在我想实现工厂模式并添加一个接口和两个更具体的实现:
public interface IRepository
{
ICollection<TModel> GetAll<TModel>() where TModel : class;
//some more functionality...
}
public class RepositoryEF6Impl : IRepository
{
protected readonly DbContext context;
public RepositoryEF6Impl(DbContext context)
{
this.context = context;
}
public ICollection<TModel> GetAll<TModel>() where TModel : class
{
return context.Set<TModel>().ToList();
}
//some more functionality...
}
现在我可以直接使用存储库,如下所示:
IRepository repo = new RepositoryEF6Impl(context);
repo.GetAll<MemberEF6Impl>();
到目前为止一切顺利。但我想用这种方式使用它:
IRepository repo = new RepositoryEF6Impl(context);
repo.GetAll<IMember>(); //note the difference
问题是数据库中没有IMember,而是一个MemberEF6Impl。
为什么我要这样使用它:
因为我们对数据库内容和viewmodel有不同的具体类,所以我必须为viewmodel创建第二个存储库,它只是具体的VMImpl类和EF6存储库之间的一个层。
public class RepositoryVMImpl : IRepository
{
protected readonly IRepository repository;
public RepositoryVMImpl(IRepository repository)
{
this.repository = repository;
}
public ICollection<TModel> GetAll<TModel>() where TModel : class
{
return repository.GetAll<TModel>();
}
}
有没有办法实现这个目标?
答案 0 :(得分:1)
我的建议是使用单个存储库,但使用一些方法重载来预测所请求的泛型类型。
方法重载:
public ICollection<TProjection> GetAll<TModel, TProjection>(Expression<Func<TModel, TProjection>> projection)
{
return context.Set<TModel>().Select(projection).ToList();
}
然后你可以使用这样的方法,它将控制返回类型。
repository.GetAll<MemberEF6Impl, IMember>(memberEF => new MemberVMImp { ... })
如果您仍需要EF实体模型作为结果类型,则可以使用当前方法:
repository.GetAll<MemberEF6Impl>();
有关EF投影的更多信息:https://www.tektutorialshub.com/projection-queries-entity-framework/
同样Automapper提供了这样的功能 - 它可以为您节省一些时间。你应该看看它。