我不能说这是最佳实践,但这就是我使用的方法,以及为什么,我们开始吧:
1. 存储库。
它们的结构是这样的:
共有三个基本接口IRead<>
,IReadCreate<>
和IReadCreateDelete<>
。
interface IRead<T>
{
T FindOne(int id);
IQueryable<T> GetOne(int id);
IQueryable<T> FindAll(Expression<Func<T, bool>> predicate);
}
interface IReadCreate<T> : IRead<T>
{
T Create();
void Create(T entity);
}
interface IReadCreateDelete<T> : IReadCreate<T>
{
void Delete(int id);
void Delete(T entity);
void DeleteWhere(Expression<Func<T, bool>> predicate);
}
所有其他接口如下所示:
interface ICategoriesRepository : IReadCreate<Category>
{
IQueryable<Category> GetAllActive();
}
它们都在它们所依赖的数据源上提供了额外的有用功能。这意味着,我无法访问我的实现存储库中的其他类型存储库。这应该在Services上完成。(往下看。)
这种方法的主要目标是显示调用代码(来自另一个程序集,因为我所有的存储库、服务和其他合同都在单独的 DLL 项目中定义(作为接口))它可以做什么(比如读取和创建项目)以及什么它不能做(比如删除项目)。
2. 服务
服务和实现业务逻辑的最佳方式。他们应该实现所有重要的逻辑方法。为了实现这种实现,他们需要一些存储库依赖,而Dependency Injector
. 我更喜欢使用Ninject,因为它允许我像这样注入依赖属性:
internal class CategoriesService : ICategoryService
{
public ICategoriesRepository CategoriesRepository { get; set; }
public IWorkstationsRepository WorkstationsRepository { get; set; }
// No constructor injection. I am too lazy for that, so the above properties
// are auto-injected with my custom ninject injection heuristic.
public void ActivateCategory(int categoryId)
{
CategoriesRepository.FindOne(categoryId).IsActive = true;
}
}
服务的目标是从控制器和存储库中消除业务逻辑。
3. 视图模型
很酷的事情,正如你所说,但原因是你为什么要自己建立它们,这是我无法理解的。我为此使用了自动映射器(带有可查询的扩展),它允许我创建如下视图:
假设我有一个需要模型的视图。IEnumerable<TicketViewModel>
我要做的是:
public class FooController : Controller
{
public IMappingEngine Mapping { get; set; } // Thing from automapper.
public ITicketsRepository TicketsRepository { get; set; }
public ViewResult Tickes()
{
return View(TicketsRepository.GetAllForToday().Project(Mapping)
.To<TicketViewModel>().ToArray();
}
}
就是这样。对存储库的简单调用,它调用底层数据源(另一种模式。我不会写它,因为它的抽象仅用于测试。),它调用数据库(或你实现的任何东西IDataSource<T>
)。Automapper 自动映射Ticket
toTicketViewModel
和 form 数据库,我检索了我的 ViewModel 列所需的唯一数据库,包括单个请求中的交叉表。
结论
还有很多要说的,但我希望这能给你一些思考。我使用的所有模式和程序都是:
- 自动映射器(映射);
- Ninject(依赖注入);
- 存储库(数据访问);
- 数据源(从数据源中读取的数据);
- 服务(数据交互);
- ViewModels(数据传输对象);
- 也许我会编辑添加其他内容。