EF N-Tier架构

3

介绍

我们需要构建一个n层应用程序,因为我们想在多个平台上共享我们的业务逻辑,并且只编写一次数据访问层(DAL)。我已经对这个主题进行了一些研究。

正如Davide Piras在他的帖子中所述:MVC3和Entity Framework,每个VS解决方案至少必须有4层。到目前为止还好。

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

问题1:

我假设,“接口”项目的接口是我的EF实体的1对1表示,这个假设正确吗?此外,这些接口应该作为不同层之间的类型使用吗?

问题2:

MSDN建议Web应用程序的DbContext的生命周期应该是每个请求一个上下文,WPF或WinForms项目的生命周期应该是每个表单一个上下文。那么,如何在不将“System.Data.Entity”添加到我的GUI层的情况下实现这一点呢?

提前感谢!


谢谢你的负评,如果我有什么不足之处,请留言告诉我。我花了很多时间和精力来提出这些问题。 - Mark Rijsmus
2个回答

3
你需要使用工作单元仓储模式,并结合像StructureMapUnity这样的依赖注入框架。基本上,你需要创建接口:
public interface IUnitOfWork
{
    void SaveChanges();
}

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

    IQueryable<TItem> Query();
}

现在,在您的DbContext类中实现上述接口,并在业务层的某个地方注册接口的实现:
public void RegisterDependencies(Container container)
{
    // Container is a Structure Map container.
    container.ForRequestedType<IUnitOfWork>()
        .CacheBy(InstanceScope.HttpContext)
        .TheDefaultConcreteType<DbContext>();    
}

请查看StructureMap Scoping Docs,了解如何配置实例的范围。

现在,完成所有代码编写后,每个需要执行一些数据操作的Business Layer类会像这样:

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创建的服务类的方法;如果您的GUI是一个ASP.NET MVC项目,则不需要创建ServiceFactory类 - 您可以从DefaultControllerFactory派生,并重写GetControllerInstance方法。有关示例,请参见此处的答案


谢谢您清晰的回复!非常有帮助。我已经了解了仓储库和UOW模式。我认为Repo的实现应该在DAL中,我是正确的吗?再次感谢。 - Mark Rijsmus
@MarkRijsmus,是的,它应该在数据访问中。 - RePierre

2
首先绝对不要在多个平台上共享您的DAL。请共享使用DAL的BL。只要您的BL代表应用程序需求的解决方案,您就不需要暴露您的DAL,也请不要这样做。此外,暴露DAL会使更多漏洞暴露给黑客,并且直接访问DAL提供了一个绕过机制,可以绕过BL中的业务逻辑、控件和验证。 答案1: 可能但不需要。考虑SOA,建议使用DTO。它们可以是实体或更复杂的组合类,由多个或部分实体组成。如果使用实体,则可以通过BL提供更大的灵活性(您可以通过一种方法调用同时发送多个数据部分),并将您的实体(以及DB结构)隐藏在第三方用户之外,从而提供更好的安全感。 答案2: 同样,考虑SOA,请勿根据用户界面构建您的BL/Service方法。BL(顾名思义)根据“工作方式”提供数据,而不是根据用户在屏幕上的“工作方式”。如果您尝试从GUI管理数据,您还将开始违反N层架构。 绝对不要在DAL之外使用任何数据特定的类和/或方法。这才是分层的真正用途。
谢谢。

谢谢您的快速回复!对不起,我的意思不是共享DAL以将其暴露给其他GUI,而只是写一次!我的错误。 - Mark Rijsmus
如果我有帮助到你,我会很高兴的。 - user3021830
先生,您也很好! - Mark Rijsmus
另一个问题:这些DTO,以及它们从实体转换而来,是否属于BLL?如果是,如何进行转换,因为您已经说明“BL(顾名思义)根据‘工作方式’提供数据,而不是根据用户在屏幕上的‘工作方式’”。您知道这方面有哪些好的例子吗?再次感谢您的所有帮助! - Mark Rijsmus
1
是的,必须在业务逻辑层完成。任何用户界面只能看到您的业务逻辑层(作为API),并且只与该层通信。如何转换数据取决于您使用的语言和/或开发偏好。在我的当前项目中,我们仅使用ADO.NET,因此我通过存储过程从数据库中获取数据并从数据访问层返回接口。在业务逻辑层中,我从接口创建模型(我的用户界面仅限于ASP.NET MVC!)并将其返回。但是,我更喜欢使用ORM工具(例如Entity Framework作为数据访问层)并编写LinQ查询以获取此结构。 - user3021830
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接