2010-06-21 190 views
1

赦免长度在这里...希望我没有走极端......适当的位置 - 业务逻辑或数据访问

我在我的第一个生产MVC工作的过程应用程序,我试图在这个过程中坚持DDD原则。我遇到了一些与如何处理应用程序的安全需求相关的问题,并认为我会看到SO社区是否可以提供一些最佳实践建议。

域信息

要使用一个简单的解释,这个应用程序将有AffiliateCompaniesUsersCustomers

  • AffiliateCompanies是层次结构,因此一个子公司可以注册并与另一个子公司的活动联系起来。根源是提供产品/服务的主要公司。
  • Users都属于一个会员实体。
  • Customers是产品/服务销往的组织。附属公司被分配给客户,使得两个不相关的分支机构有可能拆分客户。

安全信息

权限来执行应用程序中的某些行为会基于一个ACL型排列来确定。每个User对象都具有一个属性SystemAccessRules,它们确定它们可以执行哪些操作以及它们的权限范围(它们自己的对象,它们的子公司的对象或它们的整个层次结构的对象)。用户也可以属于角色,它们本身具有相同的SystemAccessRules集合。因此,如果用户登录并希望查看“他们”客户的列表,则该列表可以由他们单独分配给的客户,分配给他们的分支机构中的任何人的客户或客户组成任何人在他们的组织或任何他们的子会员组织被分配到。

数据库注意事项

DDD不谈,在某些点上存储策略已开始发挥作用。在这个简单的情况下,该表与上述对象(包括角色表),有几个支持表对齐支持对象之间的关系:

  • AffiliateCustomers - 该表允许许多一对多通过将每个实体的PK作为一对FK存储在关联公司和客户之间的关系,这些FK本身就是该表的组合PK。
  • ACL - 此表存储安全信息,特别是条目主题(用户或角色),所涉及的操作(例如“CreateCustomer”),权限(允许或拒绝)以及范围(他们自己的东西,他们的组织或他们的网络)。

The Question ...最后

我正在使用存储库和服务的组合。我试图将业务逻辑保留在服务中,并保留在存储库或数据库之外,但由于此处的安全设计,对“其”客户列表的简单请求可能会非常繁重,特别是随着数据集的增长。我试图尽可能地使用Linq,但是这种架构似乎并不适合。在我看来,这里是我的选择:

  1. 接受请求的用户作为服务方法参数(或通过上下文确定它),并有服务方法填充通过多种查询到LINQ库列表。这需要拉取客户列表,然后遍历每个客户发出另一个查询以拉取ACL数据,然后使用该数据根据权限过滤第一个列表。如果可能的话,层次问题将需要一些奇特的Linq步法(如this)。
    即使可以作出层次问题的工作,好像这个解决方案将不执行得非常好...

  2. 接受请求的用户作为一个参数,但它传递和所需的权限(例如“查看客户”)到存储库,以便通过存储过程从数据库中检索适当的数据,该存储过程将使用CTE查询中的几个EXISTS子句,这可以说明数据的层次性质以及需要检查角色和用户安全。
    这将相当数量的逻辑推送到数据库,这看起来非常反DDD并且通常很糟糕。

我靠着更倾向于第二种方案,但可能是因为在我过去的项目即是如何我已经做到了。我甚至不确定我的设计是否在正确的轨道上(过去,权限声明是使用位标志完成的,因此使用按位运算符进行数据库查询更容易)。

是否有人遇到过类似情况?如果是的话,您是否可以评论您所追求解决方案的性能和可维护性?我想坚持高尚的编程原则,但不要以简单和常识为代价。

+0

只是一个评论,而不是一个答案,但要记住KISS和YAGNI的原则。围绕存储库/服务接口设计应用程序代码,以便始终将内部数据从1更改为2.然后执行最简单,最简单的实现。例如。 2如果这是你习惯的。不要过多地投入设计,因为你错过的东西可能会在以后打破它。试着保持足够的抽象,然后逐步重构。 – queen3 2010-06-21 21:02:04

+0

是的,我正在努力抵制过度设计工程师对现在不是现实的预期需求的冲动。同时我不想让自己陷入一个角落。我想我必须做一些测试,看看它是如何通过查看列表中每个“AffiliateCompany”对象上的IEnumerable 属性的内容来评估安全性。在这一天结束的时候,这就是我将数据库中的数据放入数据库的问题......我知道数据库会更快,但我不知道速度有多快。 – 2010-06-21 21:21:40

回答

0

您是否考虑过使用specification pattern将业务规则传递给数据访问层?

该服务构造一个它传递给存储库的规范树。存储库将规范转换为Expression<Func<Customer, bool>>,并将其传递到IQueryable<Customer>.Where(...)。当储存库实现该集合时,例如通过调用ToList(),将业务规则翻译成SQL并在数据库服务器上执行。

我上次检查时,LINQ to SQL不支持CTE,因此您可能需要使用视图来扁平化层次结构。

+0

看看这种模式,我喜欢代码更易于阅读。现在我使用扩展方法Has(enum)来测试指定的安全枚举是否是用户角色的一部分,但这并不是那么糟糕。我最终以#2的方式发送用户和角色信息到数据库,并让它过滤结果。它确实有效并且表现非常好,但由于跟踪数据库更改变得更加困难,因此维护工作有点难度。对表格的更改意味着对视图,功能,sprocs等的更改 – 2011-02-11 17:40:32