7

我正在研究 SaaS 概念的多租户数据库架构设计。它将是 ASP.NET MVC -> EF,但这并不重要。

您可以在下面看到一个示例数据库模式(租户是公司)。CompanyId 在整个架构中复制,主键已放置在自然键和租户 ID 上。

当我将表添加到实体模型文件 (Model1.edmx) 中时,将此模式插入实体框架会出现以下错误:

  • 关系“FK_Order_Customer”使用外键集“{CustomerId, CompanyId}”,这些外键集部分包含在“Order”表的主键“{OrderId, CompanyId}”集中。外键集必须完全包含在主键集中,或者完全不包含在要映射到模型的主键集中。
  • 关系“FK_OrderLine_Customer”使用部分包含在表“OrderLine”的主键“{OrderLineId, CompanyId}”集中的外键集“{CustomerId, CompanyId}”。外键集必须完全包含在主键集中,或者完全不包含在要映射到模型的主键集中。
  • 关系“FK_OrderLine_Order”使用外键集“{OrderId, CompanyId}”,这些外键集部分包含在表“OrderLine”的主键集“{OrderLineId, CompanyId}”中。外键集必须完全包含在主键集中,或者完全不包含在要映射到模型的主键集中。
  • 关系“FK_Order_Customer”使用外键集“{CustomerId, CompanyId}”,这些外键集部分包含在“Order”表的主键“{OrderId, CompanyId}”集中。外键集必须完全包含在主键集中,或者完全不包含在要映射到模型的主键集中。
  • 关系“FK_OrderLine_Customer”使用部分包含在表“OrderLine”的主键“{OrderLineId, CompanyId}”集中的外键集“{CustomerId, CompanyId}”。外键集必须完全包含在主键集中,或者完全不包含在要映射到模型的主键集中。
  • 关系“FK_OrderLine_Order”使用外键集“{OrderId, CompanyId}”,这些外键集部分包含在表“OrderLine”的主键集“{OrderLineId, CompanyId}”中。外键集必须完全包含在主键集中,或者完全不包含在要映射到模型的主键集中。
  • 关系“FK_OrderLine_Product”使用外键集“{ProductId, CompanyId}”,这些外键集部分包含在表“OrderLine”的主键集“{OrderLineId, CompanyId}”中。外键集必须完全包含在主键集中,或者完全不包含在要映射到模型的主键集中。

问题分为两部分:

  1. 我的数据库设计不正确吗?我应该避免使用这些复合主键吗?我质疑我对基本模式设计(疲惫的大脑综合症)的理智。请随时提出“理想化”模式。
  2. 或者,如果数据库设计正确,那么 EF 是否无法匹配键,因为它将这些外键视为潜在的错误配置的 1:1 关系(不正确)?在这种情况下,这是一个 EF 错误吗?我该如何解决?

多租户数据库架构

4

5 回答 5

4

在快速浏览 EF 的错误消息时,它显然不喜欢您设置复合键的方式,我认为它可能会推动您朝着正确的方向前进。再想想是什么让你的主键独一无二。单独的 OrderID 不是唯一的,没有 CompanyID 吗?如果没有 CompanyID,ProductID 是否不唯一?没有 CompanyID 的 OrderLine 当然应该是唯一的,因为 OrderLine 应该只与单个订单相关联。

如果您确实需要所有这些的 CompanyID,这可能意味着有问题的公司正在为您提供 ProductID 和 OrderID,那么您可能想要采取不同的方向,并生成您自己的不是数据固有的主键. 只需为您的主键设置一个自增列,并让它们成为内部的 OrderID、OrderLineID、ProductID、CompanyID 等。此时,OrderLine 将不需要客户的 OrderID 或 CompanyID;对 Order 的外键引用将是它的起点。(并且 CustomerID 绝不应该是订单行的属性;它是订单的属性,而不是订单行。)

复合键很乱。尝试在没有它们的情况下设计模型,看看它是否简化了事情。

于 2010-05-30T12:43:06.110 回答
3

我认为错误不在设计中。不在EF中。 是在 Sql Server 关系中。

阅读 EF 消息:

关系“FK_Order_Customer”使用外键集“{CustomerId, CompanyId}”,这些外键集部分包含在“Order”表的主键“{OrderId, CompanyId}”集中。外键集必须完全包含在主键集中,或者完全不包含在要映射到模型的主键集中。

错误

实际上 Order 和 Customer 之间的关系只使用一个字段(可能您用鼠标将字段“CustomerId”从 Order 表拖到 Customer 表的“Id”)

解决方案

右键单击连接订单和客户的电线,并在关系中添加 CompanyId


PS:设计是正确的。

将 CompanyId 放在每个表中是多租户架构中的正确解决方案,因为有助于扩展(通常总是希望仅从已登录公司中选择记录)。

于 2010-11-12T09:16:04.920 回答
2

我认为将公司编号存储在每个表格中对您的伤害大于帮助。我可以理解您为什么要这样做(作为程序员/dba,您可以进入任何表并“查看”哪些数据属于谁是令人欣慰的),但它妨碍了您设置数据库它应该是这样的。

避免使用复合键,您的设计会变得更加简单。

于 2010-05-30T13:19:31.180 回答
0

如果您必须绝对将 CompanyID 列添加到每个表,请将其添加为常规列而不是复合键。当您必须实现多对多关系时,主要使用复合键。

正如有人提到的,还在 CompanyID 上创建了一个非聚集索引,因此加入到 Company 表中会受益。

谢谢!

于 2013-08-26T12:12:14.460 回答
0

首先:就像其他人说的那样,在引用外键时,使用另一个表中的整个主键(即两个字段)。

其次,我无法想象在严肃的应用程序中的大多数表中不使用 CompanyID 列。在这种情况下, Orderdetail 可能一个例外(也可能是全局查找表,除非它们依赖于租户)。问题是,如果不添加 CompanyID 或执行 JOIN 直到到达包含该列的表,您就无法对表进行任何安全的自由格式搜索。后者显然会牺牲性能。也许在这种情况下,您可以为 orderdetail 设置一个例外,只在连接的版本中搜索(只有两个表)。再说一次,它并不是真正一致的。

另外关于是否将其设置为复合键:它是可能的,但会导致错误在错误期间错误地写入信息(写入不存在或其他人的管理)的可能性。尝试在生产中解决这个问题,更不用说向客户解释为什么在他们的系统中看到他们的竞争对手订单。

于 2013-10-26T00:28:27.923 回答