2009-09-02 12 views
42

Estoy tratando de actualizar un valor de una clave primaria compuesta dentro del marco de la entidad y aparece este error: "La propiedad 'CustomerID' es parte de la información clave del objeto y . no puede ser modificado "Actualizar el valor de la clave primaria utilizando el marco de entidad

Aquí está mi código:

Dim customer As Customer = (From c In db.Customer Where c.CustomerID = "xxx" AndAlso c.SiteKey = siteKey).FirstOrDefault 
customer.CustomerID = "fasdfasdf" 
db.SaveChanges() 

parece demasiado simple. ¿Es cierto que no puede actualizar una clave principal dentro del marco de la entidad? No puedo encontrar ninguna documentación sobre el tema. ¡Gracias!

+8

¿Puedo preguntar por qué quiere cambiar la clave principal? Eso es una muy mala práctica. –

+1

Buena pregunta. Tenemos información anónima rastreada en la base de datos por su customerid anónimo. Cuando el usuario inicia sesión, quiero actualizar la tabla y configurarla para su customerid habitual. –

+4

Solo yo, tendría dos tablas una para usuarios anónimos y luego, cuando inicien sesión, crearán un nuevo registro en la tabla principal, pero nunca modificarán la primaria. –

Respuesta

10

No puede y por una buena razón. Ver los comentarios de KM.

Una cosa que digo que podría hacer es tener dos mesas una con datos anónimos y uno que almacena los datos del usuario real después de que se conecten.

O su podría (no probado o ha hecho por mí) se tiene este tipo de diseño de tabla:

---Customers---- 
AutoNumber PK <- This links to all other tables in your database, and does NOT change. 
CustomerID <- This can change. 
CustomerType <- Anonymous or logged in. 

Y cuando inician sesión, cambia el CustomerType y CustomerID a lo que necesita.

Por lo que su consulta podría tener este aspecto:

Dim customer As Customer = (From c In db.Customer _ 
          Where c.CustomerID = {Some temp ID} _ 
          AndAlso c. CustomerType = "Anonymous").FirstOrDefault 
// After user logs in. 
customer.CustomerID = {Make a new user ID here} 
customer.CustomerType = "LoggedIn" {or what ever} 
db.SaveChanges() 

en cuenta que las claves primarias autonumber Nunca cambios. Esto es para que todas las tablas que tenga en una relación con la tabla Customers sigan funcionando y no tenga que hacer actualizaciones en cascada en la clave principal (que es como apuñalarse en el ojo con un lápiz).

+1

¿Qué sucede cuando Entity Framework piensa que algo es una clave, y no veo que sea una clave en la base de datos. ¿¿Que haces entonces?? – Dexter

+35

No estoy de acuerdo con esto: "por una buena razón". Sé que es una mala práctica algunas veces, pero hay excepciones. Si estoy usando una clave natural/de varias partes para almacenar números de teléfono, por ejemplo, ¿por qué debería forzarme a crear una clave sustituta solo para actualizar el tipo de teléfono? EF debe permanecer fuera de mi negocio y hacer lo que yo le diga. Esta es una mala limitación del sistema. –

+2

"mala práctica algunas veces" Es una mala práctica todo el tiempo. Nunca he visto un caso en el que esté justificado poder cambiar la clave principal. Si solo tienes una mesa, no es gran cosa, pero si has vinculado las tablas y has empezado a jugar con las teclas principales cambiantes, puede ser muy complicado. –

19

No puede actualizar la clave principal a través del marco de la entidad, ya que el marco de la entidad no sabría qué fila de la base de datos actualizar.

Sin embargo, si realmente necesita hacerlo, podría escribir un procedimiento almacenado que actualice la clave principal y luego ejecutar el procedimiento almacenado desde el marco de la entidad.

+1

-1 nunca deberías necesitar hacerlo. El diseño de la base de datos es incorrecto si lo hace. –

+8

@Nathan, estoy de acuerdo con usted en que no debe ser necesario, solo usamos id de incremento automático. Sin embargo, la pregunta era si es posible, y esta es una forma de hacerlo. –

+0

Shiraz: este es el camino a seguir. @ Nathan: No veo por qué actualizar las claves naturales es un mal diseño de la base de datos. Ver la respuesta del Dr. A. –

-3

No puede actualizar una clave principal, pero eso no es una limitación del marco de entidad, sino una regla fundamental de desarrollo de base de datos. Una clave principal se asigna una vez a una fila en una tabla y hace que esta fila sea única.
Quizás pueda actualizar la clave de alguna manera, pero esto viola definitivamente la definición de una clave principal.

Así que, simplemente no lo hagas, hay otras maneras de lograr lo que estás tratando de hacer.

+1

es una regla de oro obsoleta y ciertamente no es fundamental. como las actualizaciones en cascada en un col todo se mantiene sincronizado, a menos que tenga datos fuera de su base de datos (que es malo) no hay problema – markmnl

53

Tengo un Ph.D. en cs: en el área de Bases de datos, esta respuesta será un poco diferente de la perspectiva de los programadores. Con todo respeto a Oliver Hanappi, una clave puede cambiar ocasionalmente si no es una clave sustituta. P.ej. Una clave natural o una clave compuesta. Por ejemplo. Es posible obtener su SSN cambiado en los Estados Unidos. Pero muchos programadores a lo largo de los años considerarían esta clave como inmutable y la usarían como tal. Es mucho más común cambiar una clave primaria compuesta compuesta por claves externas.

Estoy tratando con una base de datos que tiene una relación ternaria. Específicamente tres entidades (con claves externas que son claves primarias sustitutas en sus tablas respectivas). Sin embargo, para preservar la relación entre dos entidades al cambiar la tercera entidad, requiere cambiando parte de la tabla primaria de la tabla de intersección (también llamada tabla de unión pura en MSDN).Este es un diseño válido y solo podría mejorarse eliminando la tabla de intersecciones de relaciones ternarias y reemplazándola con dos tablas de relaciones binarias (que pueden tener sus propias claves sustitutas). EF manejaría esto bien. Este cambio de diseño haría un modelo (Muchos-> Muchos) -> Muchos o Padres1-Padres2-> Hijo-nieto (si no está claro, lea el ejemplo a continuación). El marco de la entidad funcionaría bien con esto ya que cada relación es realmente una relación de uno a muchos. Pero es un diseño loco desde una perspectiva DB. Déjame mostrarte un ejemplo de por qué.

Considere que el Curso, el Aula y el Instructor están asociados entre sí en una clase. La clase podría incluir: CourseID, ClassroomID, InstructorID como claves foráneas y contener una clave primaria compuesta que incluya las tres. Aunque es un modelo ternario claro y conciso (relación de 3 vías) podríamos dividirlo en relaciones binarias. Esto daría dos tablas de intersección. Adición de claves sustitutas satisfarían EF como sigue:

Class (SurrogateKeyClass, InstructorID, courseid)

ClassRoomUsed (SurrogateKeyClassroomUsed, SurrogateKeyClass, ClassRoomID)

El problema con este diseño es que podríamos tener el mismo curso y el instructor asociado mult veces, lo que el modelo anterior evita. Para evitar este problema, puede agregar una restricción en la base de datos para la unicidad de los dos campos ID, pero ¿por qué querría hacer esto cuando solo está tratando con claves sustitutas para empezar? Sin embargo, esta solución funcionaría lo mejor que puedo decir. Sin embargo, este no es un diseño de base de datos lógica debido a la restricción única no natural requerida en el DB.

PERO, si no desea cambiar su base de datos o no puede cambiar su base de datos, aquí hay una segunda solución : Las tablas de intersección/asociación son solo eso, enlaces que unen dos o más entidades. Si uno cambia, elimine la asociación y vuelva a crear una nueva que tenga las claves externas apropiadas (propiedades de navegación). Eso significa que no se le permitirá requerir entidades secundarias en ninguna de las relaciones, pero eso es extremadamente común.

¡Sugeriría que Entity Framework (en el futuro) nos permita a aquellos de nosotros que podemos diseñar un elegante modelo de DB cambiar partes de claves en tablas de intersección/asociación cuando queramos!

Otro ejemplo de forma gratuita:

Considere un estudiante, curso, Asociación grado. Los estudiantes están asociados con un curso por un grado. Por lo general, esta es una asociación muchos a muchos entre Estudiante y un Curso con un campo adicional en la tabla de asociación llamado grado (las tablas de asociación tienen datos de carga útil como grado, las tablas de intersección no tienen una carga útil y se hace referencia en MSDN como tablas de unión pura en ceder en un solo lugar):

Estudiante (studentID, ....)

de golf (courseid, ...)

tomando (studentID, courseid, grado)

Si alguien presenta un error de entrada de datos de un desplegable y pone a un estudiante en la clase equivocada, te gusta que cambien más tarde seleccionando la desplegable de nuevo y seleccionando un curso diferente. En el fondo, tendrá que eliminar el objeto EF de la tabla Toma y volver a crearlo sin perder una calificación, si es que hay una. Simplemente cambiando la clave externa CourseID parece una mejor alternativa. Propón tu propia asociación si esta parece artificial, pero como profesor fue natural para mí.

Conclusión: cuando tiene una cadena de relaciones, puede ser mejor no permitir la conexión en cascada y/o cambiar FK, pero existen escenarios razonables/lógicos donde es necesario, incluso si no se recomienda como una mejor práctica en general.

Este problema puede manifestarse con las siguientes excepciones dependiendo de si va a cambiar la propiedad de navegación o la propiedad clave en el modelo, respectivamente:

ha producido un referencial violación de restricción de integridad: Una propiedad clave principal que es una parte de restricción de integridad referencial no se puede cambiar cuando el objeto dependiente no se modifica a menos que se establezca en el objeto principal de la asociación. El objeto principal debe rastrearse y no marcarse para su eliminación.

La propiedad 'X' es parte de la información de la clave del objeto y no se puede modificar.

+0

Tengo exactamente esta situación y sus comentarios son acertados. – xan

+1

Muy buena respuesta. Usualmente uso PK sustitutivas "por consistencia" (e introduzco otras CK según se requiera), excepto cuando se usan como una tabla de unión donde siempre parecen ser un error terrible. El ejemplo tiene bastante sentido. – user2246674

Cuestiones relacionadas