带接口的 ef6 中的存储库模式
repository pattern in ef6 with Interfaces
a让我们有一个简单的场景:
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...
}
我在我们的程序中有所有接口的两个具体实现。一种专门用于数据库迁移的实现,一种用于我们的视图模型。现在我想实现 factory-pattern 并添加一个接口和两个具体实现:
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。
为什么我要这样使用它:
因为我们对数据库和视图模型有不同的具体 classes,我还必须为视图模型创建第二个存储库,它只是具体 VMImpl class 和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>();
}
}
有办法实现吗?
我的建议是使用单一存储库,但使用一些方法重载来投影请求的泛型类型。
方法重载:
public ICollection<TProjection> GetAll<TModel, TProjection>(Expression<Func<TModel, TProjection>> projection)
{
return context.Set<TModel>().Select(projection).ToList();
}
那么你可以使用这样的方法,这将控制 return 类型。
repository.GetAll<MemberEF6Impl, IMember>(memberEF => new MemberVMImp { ... })
如果您仍然需要 EF 实体模型作为结果类型,您可以使用当前的方法:
repository.GetAll<MemberEF6Impl>();
有关 EF 投影的更多信息:https://www.tektutorialshub.com/projection-queries-entity-framework/
Automapper 也提供了这样的功能 - 它可以节省您一些时间。你应该检查一下。
a让我们有一个简单的场景:
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...
}
我在我们的程序中有所有接口的两个具体实现。一种专门用于数据库迁移的实现,一种用于我们的视图模型。现在我想实现 factory-pattern 并添加一个接口和两个具体实现:
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。
为什么我要这样使用它:
因为我们对数据库和视图模型有不同的具体 classes,我还必须为视图模型创建第二个存储库,它只是具体 VMImpl class 和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>();
}
}
有办法实现吗?
我的建议是使用单一存储库,但使用一些方法重载来投影请求的泛型类型。
方法重载:
public ICollection<TProjection> GetAll<TModel, TProjection>(Expression<Func<TModel, TProjection>> projection)
{
return context.Set<TModel>().Select(projection).ToList();
}
那么你可以使用这样的方法,这将控制 return 类型。
repository.GetAll<MemberEF6Impl, IMember>(memberEF => new MemberVMImp { ... })
如果您仍然需要 EF 实体模型作为结果类型,您可以使用当前的方法:
repository.GetAll<MemberEF6Impl>();
有关 EF 投影的更多信息:https://www.tektutorialshub.com/projection-queries-entity-framework/
Automapper 也提供了这样的功能 - 它可以节省您一些时间。你应该检查一下。