1

我正在使用SQL Server 2008/LinqToSQL /定制存储库作为DAL的多用户互联网数据库驱动的网站。我遇到了一个规范化问题,如果正确利用,会导致数据库状态不一致,我想知道如何处理这个问题。如何避免此数据库模式中的冲突数据?

问题:几个不同的公司有权访问我的网站。他们应该能够在我的网站上跟踪他们的项目和客户。一些(但不是全部)项目应该分配给客户。

这将导致以下数据库模式:

**Companies:** 
ID 
CompanyName 

**Clients:** 
ID 
CompanyID (not nullable) 
FirstName 
LastName 


**Projects:** 
ID 
CompanyID (not nullable) 
ClientID (nullable) 
ProjectName 

这导致以下关系:

Companies-Clients (1:n) 
Companies-Projects (1:n) 
Clients-Projects(1:n) 

现在,如果用户是恶意的,他可能例如插入一个项目他自己的CompanyID,但具有属于另一个用户的ClientID,导致数据库处于不一致状态。

问题以类似的方式发生在我的数据库模式上,所以我想以通用的方式解决这个问题。我有以下两种想法:

  • 检查可能导致DAL不一致的数据库写入。这是通用的,但在更新和创建查询之前需要额外的数据库查询,因此会导致性能下降。

  • 为客户 - 项目关系创建一个附加表并确保以此方式创建的关系是一致的。这也需要一些额外的选择查询,但远低于第一种情况。另一方面,它不是通用的,所以从长远来看,更容易错过某些东西,尤其是在向数据库添加更多表/依赖项时。

你会做什么?我错过了更好的解决方案吗?

编辑:你可能想知道为什么Projects表有一个CompanyID。这是因为我希望用户能够使用和不使用客户端来添加项目。我需要跟踪哪个公司(以及哪个网站用户)属于无客户端项目,这就是为什么项目需要公司ID。

回答

0

最后,我实现了一个完全通用的解决方案,它可以解决我的问题,而无需太多的运行时间开销,也不需要对数据库进行任何更改。我会在这里描述它以防别人遇到同样的问题。

首先,该方法仅适用,因为其他表通过多个路径引用的唯一表是公司表。由于在我的数据库中就是这种情况,我只需检查每个要创建/更新/删除的实体的所有n:1引用实体是否引用同一家公司(或根本没有公司)。

我通过获得所有我的LINQ实体从以下类型中的一种执行这样的:

  1. SingleReferenceEntityBase - 限额。只有(通过反思)检查公司表中是否只有一个参考(无论是过渡性的还是不敏感的)。如果是这种情况,那么对公司表的引用不会变得不一致。

  2. MultiReferenceEntityBase - 对于特殊情况,例如上面的Projects表。询问所有直接引用的实体所引用的公司ID。如果不一致,则引发异常。这会使我为每个CRUD操作选择几个查询,但由于MultiReferenceEntities比SingleReferenceEntities少得多,所以这可以忽略不计。

这两种类型的实施“CheckReferences”和我打电话它每当LINQ实体通过部分地实现该自动生成的OnValidate(System.Data.Linq.ChangeAction动作)方法写入到数据库适用于所有Linq实体。

0

如果你想使用这样的表,并避免所有新的查询只是把触发器放在表上,当用户试图插入错误的数据行触发器阻止他。 最好的问候, Iordan

+0

我认为重点在于,如果没有某种方法记录数据库中允许或不允许的内容,触发器无法确定实际上有效的数据是否有意义。 – ninesided 2009-08-05 08:25:50

+0

正是。我可能会尝试在我的DAL中执行相同的操作,而不是使用触发器,但我需要为每个更新/插入/删除操作添加一些额外的select查询,这将导致我在上面提到的第一种可能的解决方案。 – 2009-08-05 08:37:19

2

我愿意与后者,有一个或多个表,定义实体之间的允许关系。

1

请注意,您的参考文献中没有循环,因此标题具有误导性。

你有什么是冲突的数据的可能性,这是不同的。


为什么在项目表中有“CompanyID”?涉及的公司的ID由您链接的客户端隐式给出。你不需要它。

删除该列并删除了问题。

此外,客户端表中“名称”列的用途是什么?你能为客户提供一个与公司名称不同的名称吗?

或者是“客户”在那家公司的人?


编辑:确定与澄清有关项目没有公司,我会单独拿出来引用,但你不会摆脱您所描述的问题不在于防止多个引用被限制制作。

现有表的一个简单约束是,项目行的CompanyID和ClientID字段不能同时为非null。

+0

请参阅我的编辑上面的澄清 – 2009-08-05 12:12:59

0

我的第一个想法是为名称为“无客户”的每家公司创建一个特殊的客户记录。然后从Project表中删除CompanyId,如果项目没有客户端,请使用“无客户端”记录而不是“正常”客户端记录。如果处理这样的非客户端是特殊的,则向无客户端记录添加标志以明确标识它。 (我不愿意依赖名称是“没有客户端”或类似的东西 - 太模糊了)。

然后就没有办法存储不一致的数据,所以问题就会消失。