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 Work
和 Repository
模式与 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。
简介
我们需要构建一个 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 Work
和 Repository
模式与 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。