EF N 层架构

EF N-Tier Architecture

简介

我们需要构建一个 n 层应用程序,因为我们希望在多个平台上共享我们的 BL 并且只编写一次 DAL。我已经对这个问题做了一些研究。

正如在 Davide Piras 的 post 中所读:MVC3 and Entity Framework 每个 VS 解决方案必须至少有 4 层。到目前为止一切顺利。

他还指出,DAL 项目是唯一被允许甚至知道正在使用 EF 的项目。

问题一:

我假设 'Interfaces' 项目的接口是我的 EF 实体的一对一表示,我对此是否正确?另外,这些接口应该用作不同层之间的类型吗?

问题二:

MSDN 建议 DbContext 的生命周期应该是 WebApps 的每个请求一个上下文,以及 WPF 或 WinForms 项目中的每个表单一个上下文。那么,如何在不向我的 GUI 层添加 'System.Data.Entity' 的情况下实现这一点?

提前致谢!

首先请勿!!!在多个平台上共享您的 DAL。分享你使用 DAL 的 BL。只要您的 BL 代表您的应用程序需求的解决方案,您就不需要公开您的 DAL,也请不要公开。此外,公开 DAL 的缺点是会将更多漏洞暴露给黑客,并且直接访问 DAL 会为您的 BL 中的业务逻辑、控制和验证提供 btpass 机制。

答案 1: 可能但不需要。考虑到 SOA,我建议使用 DTO。它们要么是实体,要么是更复杂的复合 class 几个 and/or 部分实体。如果您使用实体,这会让您更灵活地通过 BL 提供信息(您可以通过一个方法调用一次发送多个数据部分),并向第三方用户隐藏您的实体(也是数据库结构),从而提供更好的安全感。

答案2: 同样,考虑到 SOA,不要根据用户界面构建 BL/Service 方法。 BL(顾名思义)根据“工作如何完成”而不是“用户在屏幕上如何完成工作[=27=”提供数据]”。如果您尝试从 GUI 管理数据,您也会开始违反 N 层架构。 请勿!!! 在 DAL 之外使用任何数据特定 class and/or 方法。这才是分层的真正用途。

此致。

您需要将 Unit of WorkRepository 模式与 StructureMap or Unity 等依赖注入框架一起使用。

基本上,您需要做的就是创建接口:

public interface IUnitOfWork
{
    void SaveChanges();
}

public interface IRepository<TItem>
{
    TItem GetByKey<TKey>();

    IQueryable<TItem> Query();
}

现在,在您的 DbContext class 中实现上面的接口,并在业务层的某处注册接口的实现:

public void RegisterDependencies(Container container)
{
    // Container is a Structure Map container.
    container.ForRequestedType<IUnitOfWork>()
        .CacheBy(InstanceScope.HttpContext)
        .TheDefaultConcreteType<DbContext>();    
}

有关如何配置实例范围的信息,请参见StructureMap Scoping Docs

现在,所有这些代码都准备好了,每个需要执行一些数据操作的 Business Layer class 看起来像这样:

public class SomeService
{
    public SomeService(IRepository<SomeItem> repository, IUnitOfWork unitOfWork)
    {
        this.repository = repository;
        this.unitOfWork = unitOfWork;
    }

    public void MarkItemCompleted(int itemId)
    {
        var item = repository.GetByKey(itemId);
        if(item != null)
        {
            item.Completed = true;
            unitOfWork.SaveChanges();
        }
    }
}

现在,将服务的创建隐藏在工厂后面:

public class ServiceFactory
{
    private readonly Container container;// = initialize the container

    public TService CreateService<TService>()
    {
        return container.GetInstance<TService>();
    }
}

并且在您的 GUI 层中仅调用通过 ServiceFactory 创建的服务 class 方法;如果您的 GUI 是 ASP.NET MVC 项目,则无需创建 ServiceFactory class - 您可以从 DefaultControllerFactory 派生并覆盖 GetControllerInstance 方法。有关示例,请参阅 the answer here