2010-05-30 5 views
7

Estoy mirando el diseño de esquema de base de datos de múltiples inquilinos para un concepto de SaaS. Será ASP.NET MVC -> EF, pero eso no es tan importante.Diseño de base de datos de Entity Framework y multi-tenancy

A continuación puede ver un esquema de base de datos de ejemplo (el Inquilino es la Compañía). El CompanyId se replica en todo el esquema y la clave principal se ha colocado tanto en la clave natural como en el ID del inquilino.

conecta este esquema en el marco de la entidad da los siguientes errores cuando agrego las tablas en el archivo de modelo de entidad (Model1.edmx):

  • La relación 'FK_Order_Customer' utiliza el conjunto de claves externas '{CustomerId, CompanyId}' que están parcialmente contenidos en el conjunto de claves principales '{OrderId, CompanyId}' de la tabla 'Pedido'. El conjunto de claves externas debe estar completamente contenido en el conjunto de claves primarias, o completamente no incluido en el conjunto de claves primarias que se asignarán a un modelo.
  • La relación 'FK_OrderLine_Customer' usa el conjunto de claves externas '{CustomerId, CompanyId}' que están parcialmente contenidas en el conjunto de claves principales '{OrderLineId, CompanyId}' de la tabla 'OrderLine'. El conjunto de claves externas debe estar completamente contenido en el conjunto de claves primarias, o completamente no incluido en el conjunto de claves primarias que se asignarán a un modelo.
  • La relación 'FK_OrderLine_Order' utiliza el conjunto de claves foráneas '{OrderId, CompanyId}' que están parcialmente contenidas en el conjunto de claves primarias '{OrderLineId, CompanyId}' de la tabla 'OrderLine'. El conjunto de claves externas debe estar completamente contenido en el conjunto de claves primarias, o completamente no incluido en el conjunto de claves primarias que se asignarán a un modelo.
  • La relación 'FK_Order_Customer' usa el conjunto de claves externas '{CustomerId, CompanyId}' que están parcialmente contenidas en el conjunto de claves primarias '{OrderId, CompanyId}' de la tabla 'Orden'. El conjunto de claves externas debe estar completamente contenido en el conjunto de claves primarias, o completamente no incluido en el conjunto de claves primarias que se asignarán a un modelo.
  • La relación 'FK_OrderLine_Customer' usa el conjunto de claves externas '{CustomerId, CompanyId}' que están parcialmente contenidas en el conjunto de claves principales '{OrderLineId, CompanyId}' de la tabla 'OrderLine'. El conjunto de claves externas debe estar completamente contenido en el conjunto de claves primarias, o completamente no incluido en el conjunto de claves primarias que se asignarán a un modelo.
  • La relación 'FK_OrderLine_Order' utiliza el conjunto de claves foráneas '{OrderId, CompanyId}' que están parcialmente contenidas en el conjunto de claves primarias '{OrderLineId, CompanyId}' de la tabla 'OrderLine'. El conjunto de claves externas debe estar completamente contenido en el conjunto de claves primarias, o completamente no incluido en el conjunto de claves primarias que se asignarán a un modelo.
  • La relación 'FK_OrderLine_Product' utiliza el conjunto de claves foráneas '{ProductId, CompanyId}' que están parcialmente contenidas en el conjunto de claves principales '{OrderLineId, CompanyId}' de la tabla 'OrderLine'. El conjunto de claves externas debe estar completamente contenido en el conjunto de claves primarias, o completamente no incluido en el conjunto de claves primarias que se asignarán a un modelo.

La pregunta es en dos partes:

  1. es mi diseño de la base de datos incorrectos? ¿Debería abstenerme de estas claves primarias compuestas? Estoy cuestionando mi cordura con respecto al diseño de esquema fundamental (síndrome de cerebro agotado). Por favor, siéntase libre de sugerir el esquema 'idealizado'.
  2. Alternativamente, si el diseño de la base de datos es correcto, entonces ¿EF no puede hacer coincidir las claves porque percibe estas claves foráneas como posibles relaciones erróneas 1: 1 (incorrectamente)? En ese caso, ¿se trata de un error de EF y cómo puedo solucionarlo?

Multi-tenancy database schema http://i46.tinypic.com/23si52u.png

+0

Si elimino las claves primarias compuestas y solo uso las teclas naturales (IdProducto, ID de pedido, Id. De cliente, Id. De línea de pedido), el error EF desaparece. Sin embargo, no estoy seguro de si eso es simplemente meter la basura debajo de la alfombra. – Junto

+0

Una clave principal debe cumplir dos requisitos. Primero, debe ser único. Segundo, para la normalización, todos los elementos no clave deben ser completamente dependientes de la clave primaria. Algunas de sus claves compuestas rompen la normalización bastante mal, porque parece que un componente de su clave compuesta depende de la otra parte de la clave compuesta. Es un riesgo importante con las teclas compuestas. Entonces, para responder a su inquietud, ¡no * no * simplemente está metiendo basura debajo de la alfombra! –

Respuesta

4

En un análisis rápido de los mensajes de error de EF, está claro que no le gusta la forma en que está la creación de claves compuestas, y creo que es probable que empujando en la dirección correcta. Reflexione sobre qué hace que sus claves principales sean únicas. ¿El OrderID solo no es único, sin un ID de empresa? ¿Un ProductID no es exclusivo, sin un ID de empresa? Un OrderLine ciertamente debe ser único sin un ID de empresa, ya que un OrderLine debe asociarse solo con un solo pedido.

Si realmente necesita el ID de empresa para todos estos, lo que probablemente signifique que la empresa en cuestión le está suministrando ProductID y OrderID, entonces es posible que desee ir en otra dirección y generar sus propias claves principales que no son intrínseco a los datos. Simplemente configure una columna de autoincremento para su clave principal, y permita que sean el ID de pedido interno, ID de línea de pedido, ID de producto, ID de empresa, etc. En ese punto, OrderLine no necesitará el Id. De pedido ni la Id. De compañía del cliente; la referencia de la clave externa a la Orden sería su punto de partida. (Y CustomerID nunca debe ser un atributo de una línea de pedido, es un atributo del pedido, no la línea de pedido).

Las claves compuestas son simplemente desordenadas. Intente diseñar el modelo sin ellos y vea si simplifica las cosas.

+0

Estoy de acuerdo con las teclas compuestas. ¡Ni siquiera estoy seguro de por qué los agregué en primer lugar! La programación a altas horas de la noche nunca es una buena idea para mí. – Junto

+0

Voy a dar la respuesta a Cylon Cat en lugar de a EJB, principalmente porque desencadenó mis procesos de pensamiento acerca de por qué había agregado las teclas compuestas en primer lugar (incorrectamente). Gracias a ambos. – Junto

+0

No estoy de acuerdo. La causa del error son los campos que Junto no utilizó cuando creó las relaciones entre tablas. Id. De la empresa en cada tabla ayuda mucho en sitios multi-tenant. –

2

Creo que almacenar el número de la compañía en cada una de las tablas le hace más daño que ayudar. Puedo entender por qué quieres hacer esto (como el programador/dba puedes simplemente entrar en cualquier tabla y "ver" qué datos pertenecen a quién es reconfortante), pero se interpone en el camino de configurar la base de datos. como debería ser

Evite las teclas compuestas y su diseño se vuelve mucho más simple.

+0

De acuerdo. Claves compuestas binned – Junto

2

Creo que el error no está en el diseño. No está en EF. Está en las relaciones del servidor Sql.

Lea el mensaje EF:

La relación 'FK_Order_Customer' utiliza el conjunto de claves externas '{CustomerId, CompanyID}' que se parcialmente contenido en el conjunto de claves primarias '{ OrderId, CompanyId} 'de la tabla' Pedido '. El conjunto de claves extranjeras debe estar completamente contenido en el conjunto de claves primarias , o completamente no en el conjunto de claves principales que se asignará a un modelo.

ERROR

podía comprender la relación Transcurrirá Orden y el uso de los clientes un solo campo (probablemente ha arrastrado con el ratón el campo "CustomerId" de teh tabla Order a la "identificación" de la tabla de clientes)

SOLUCIÓN

clic derecho en el cable que conecta Orden y de atención al cliente y en la relación añadir también la CompanyID


PD: El diseño es correcto.

Poner el identificador de empresa en cada tabla es una solución definitiva en la arquitectura multi-tenant porque ayuda a escalar (generalmente siempre se desean seleccionar solo los registros de la compañía registrada).

+0

no hay una verdad absoluta ni en la frase "No usar claves compuestas" en "Utilizar siempre para multitenancy". Depende del uso de la base de datos y el uso de lo pasional. en las bases de datos DWH me gustaría usar claves compuestas. en OLTP probablemente aún crearía la columna CompanyID en cada tabla que representa una entidad raíz con un índice no agrupado, pero no veo por qué necesito hacer que forme parte de la clave ... y puede que no sea para agregar a entidades que no sean raíz como Order lines –

0

Si tiene que agregar absolutamente la columna CompanyID a cada tabla, agréguela como una columna normal y no como una clave compuesta. La clave compuesta se usa principalmente cuando tiene que implementar una relación de muchos a muchos.

Como alguien mencionado también crea un índice no agrupado en CompanyID, por lo que se benefician las uniones a la tabla Company.

Gracias!

0

Primero: como otros dijeron, al hacer referencia a una clave externa, use la clave primaria completa en la otra tabla (es decir, ambos campos).

En segundo lugar, no puedo imaginar no usar una columna CompanyID en la mayoría de las tablas en una aplicación seria. Orderdetail podría ser quizás sea una excepción en este caso (también tablas de búsqueda globales quizás, a menos que dependan del inquilino). La cosa es que no se puede hacer ningún tipo de búsqueda segura de forma libre en una tabla sin agregar el ID de la Compañía, o realizar uniones hasta el momento en que llegue a una tabla que tenga esa columna. El último obviamente cuesta el rendimiento. Quizás en este caso podría hacer una excepción para orderdetail y solo buscar en la versión unida (solo dos tablas). Por otra parte, no es realmente consistente.

También con respecto a hacer una tecla compuesta o no: es posible, pero abre la posibilidad de que un error escriba información incorrectamente (en administraciones inexistentes o ajenas) durante la duración del error. Intenta arreglar eso en producción, sin mencionar explicarle a los clientes por qué están viendo las órdenes de sus competidores en su sistema.

+0

Después de juguetear con varios ORM, he llegado a la conclusión de que al usar join tables en relaciones n: m, probablemente estos podrían excluirse de tener el inquilino (al menos en su mayoría). Los ORM tienden a dar problemas con esto y, en realidad, cualquier consulta que involucre una tabla de unión tendrá al menos otra tabla que contenga un inquilino. Muy rara vez tendrías que consultarlas por sí mismos, resolverse fácilmente uniéndolo a una tabla adyacente. – user2921878

Cuestiones relacionadas