2010-02-11 19 views
5

Esto parece que debería ser bastante obvio, pero algo sobre el marco de la entidad me está confundiendo y no puedo hacer que esto funcione.Cómo insertar o actualizar muchas tablas en .NET entidad framework

En pocas palabras, tengo tres mesas donde los valores de identidad son las columnas de identidad: Usuarios (ID de usuario, nombre de usuario) Categorías (categoryId, categoryName) joinTable (identificación de usuario, CategoryId) compuesto.

En el diseñador de entidades (esto es .net 4.0), cuando importo estas tablas, como se esperaba, la tabla de unión no aparece pero los Usuarios y las Categorías muestran una relación. El siguiente código:

var _context = new MyContext(); 
var myUser = new User(); 
myUser.UserName = "joe"; 

var myCategory = new Category(); 
myCategory.CategoryName = "friends"; 

_context.Users.AddObject(myUser); 
myUser.Categories.Add(myCategory); 

var saved = _context.SaveChanges(); 

devuelve un error de (aunque nada ha sido añadido a la base de datos):

An item with the same key has already been added. 

Si añado lo siguiente antes de guardar:

_context.Categories.AddObject(myCategory); 
myCategory.Users.Add(myUser); 

tengo la mismo error y nada guardado en el db. Si salvo el myUser y el objeto myCategory antes de intentar asociar ellos, tanto ahorrar, pero el segundo salvamento arroja un error, sin nada añadido a la tabla de unión:

Cannot insert the value NULL into column 'UserId', table '...dbo.JoinTable'; column does not allow nulls. INSERT fails. The statement has been terminated. 

estoy claramente no entender cuántos a muchas relaciones se insertan. ¿Qué me estoy perdiendo?

+0

¿Cuál es el tipo de sus propiedades de identificación? –

+0

int, identitity –

+0

Aún estoy tratando de resolver esto. Al agregar un tercer campo espurio a la tabla de unión (DateCreated), puedo forzar al diseñador de la entidad a mostrar la tabla de unión. Luego puedo definir las relaciones: var myJoin = new JoinTable {UserId = myUser.UserId, CategoryId = myCategory.CategoryId}; Y, a continuación, se insertará correctamente al guardar: _context.Categories.AddObject (myCategory); myCategory.JoinTables.Add (myJoin); myJoin.User = myUser; –

Respuesta

5

No necesita llamar a SaveChanges() después de agregar entidades de usuario y categoría a la base de datos, y luego establecer su asociación entre ellas.

Sin embargo, el problema real aquí es la segunda excepción que enumeró. Si nos fijamos en SQLProfiler o el perfilador ADO.NET dentro del depurador, verá que durante el segundo SaveChanges llama se ve algo como esto:

insert [dbo].[JoinTable]([UserId]) values (@0) select [CategoryId] from 
[dbo].[JoinTable] where @@ROWCOUNT > 0 and [UserId] = @0 and [CategoryId] = scope_identity() 

Obviamente, esto no funcionará si ha programado el joinTable correctamente (compuesto PK en ambas columnas).

Si miro el almacén EntityModel a través del Explorador de modelos, se muestra que la columna CategoryId dentro de JoinTable sí tiene StoreGeneratedPattern en Identity mientras UserId está establecido en None. El por qué EF hizo esto durante la fase de generación cuando una PK compuesta estaba presente está más allá de mí. Publicaré un error sobre esto a MS, sin embargo, mientras tanto, puede editar manualmente el archivo edmx/ssdl después de la generación para eliminar el especificador de identidad.Encuentra la = cadena StoreGeneratedPattern "Identidad" bajo la etiqueta de propiedad de la etiqueta EntityType para su joinTable y eliminarlo:

Cambio:

<Property Name="CategoryId" Type="int" Nullable="false" StoreGeneratedPattern="Identity" /> 

Para:

<Property Name="CategoryId" Type="int" Nullable="false" /> 

Luego, cuando se ejecuta el código obtendrá una mejor inserción de consulta (¡y no más excepciones!):

insert [dbo].[JoinTable]([UserId], [CategoryId]) values (@0, @1) 
1

La forma en que he hecho esto es generar primero una entidad de categoría válida con la clave de entidad.

Category myCategory = _context.Categories.First(i => i.CategoryID == categoryIDToUse); 

O puede tratar de crear la entidad como un talón para guardar el golpe a la base de datos:

Category myCategory = new Category{CategoryID = categoryIDToUse }; 

A continuación, agregue esa entidad al conjunto de entidades (CategorySet) en el ObjectContext utilizando el Adjuntarpara método (es posible que desee comprobar si ya está conectado). Luego puede agregar la Categoría a su entidad de Usuario usando el método Agregar. Algo como esto:

myUser.Categories.Add(myCategory); 

SaveChanges de llamadas(). Eso ha funcionado para mi.

+0

Quizás esto es un cambio con 4.0, pero no hay ningún objeto 'categoryset' en myUser, pero hay 'categorías': myUser.Categories.Add (myCategory); Pero esto ya lo tengo en mi ejemplo de código anterior. Aunque no estoy seguro de qué quiere decir con respecto a la "generación de una categoría válida con la clave de la entidad". –

+0

Estoy usando EF v1.0. Actualicé mi respuesta. Por 'categoryset' me refería a cualquier cosa que tu nombre de EntitySet fuera para las entidades de Categoría. Veo que es 'Categorías' y he actualizado el ejemplo del código. Espero que esto ayude. – DaveB

+0

Bien, lamentablemente esto es lo que he hecho con los resultados que se muestran arriba. Usando: myCategory.Users.Add (myUser) Y/O myUser.Categories.Add (myCategory) devuelve el 'un elemento con la misma clave ya ha sido agregado' –

Cuestiones relacionadas