5

Cela semble être assez évident, mais quelque chose dans le framework d'entité me trouble et je n'arrive pas à le faire fonctionner.Comment insérer ou mettre à jour de nombreuses tables dans un framework d'infrastructure .net

Tout simplement, j'ai trois tables où les valeurs d'identification sont des colonnes d'identité: utilisateurs (nom d'utilisateur), userId Catégories (CategoryId, categoryName) joinTable (UserId, CategoryId) composite.

Dans le concepteur d'entités (c'est .net 4.0), lorsque j'importe ces tables, comme prévu, la table de jointure n'apparaît pas mais les utilisateurs et les catégories affichent une relation. Le code suivant:

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(); 

Renvoie une erreur de (bien que rien n'a été ajouté à la base de données):

An item with the same key has already been added. 

Si j'ajoute les éléments suivants avant d'enregistrer:

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

Je reçois la même erreur et rien enregistré dans la base de données. Si je sauve le myUser et l'objet myCategory avant d'essayer de les associer, ils ont tous deux sauver, mais le second sauvegarde jette une erreur, rien ajouté à la table de jointure:

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

Je suis bien ne pas comprendre combien à beaucoup de relations sont insérées. Qu'est-ce que je rate?

+0

Quel est le type de vos propriétés d'identité? –

+0

int, identitity –

+0

Toujours en train d'essayer de comprendre cela. En ajoutant un troisième champ erroné à la table de jointure (DateCreated), je peux forcer le concepteur d'entité à afficher la table de jointure. Je peux ensuite définir les relations: var myJoin = nouveau JoinTable {UserId = myUser.UserId, CategoryId = myCategory.CategoryId}; Ensuite, les éléments suivants seront insérés correctement lors de l'enregistrement: _context.Categories.AddObject (myCategory); myCategory.JoinTables.Add (myJoin); myJoin.User = myUser; –

Répondre

5

Vous devez appeler SaveChanges() après avoir ajouté des entités User et Category à la base de données, puis définir votre association entre eux.

Cependant, le vrai problème ici est la deuxième exception que vous avez listée. Si vous regardez SQLProfiler ou le profileur de ADO.NET dans le débogueur, vous verrez que pendant la deuxième SaveChanges appelez ressemble à ceci:

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

Évidemment, cela ne fonctionnera pas si vous programmez votre joinTable correctement (composite PK sur les deux colonnes). Si je regarde le magasin EntityModel via le navigateur de modèles, cela montre que la colonne CategoryId dans JoinTable a en effet StoreGeneratedPattern définie sur Identity alors que UserId est défini sur None. Pourquoi EF l'a fait pendant la phase de génération quand un PK composite était présent est au-delà de moi. Je vais signaler un bug à MS, mais en attendant, vous pouvez éditer manuellement le fichier edmx/ssdl après la génération pour supprimer le spécificateur d'identité.Trouvez la StoreGeneratedPattern = chaîne "d'identité" sous l'étiquette de propriété de la balise EntityType pour votre joinTable et retirez-le:

Change:

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

Pour:

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

Ensuite, lorsque vous exécutez votre code vous obtiendrez une requête d'insertion beaucoup mieux (et plus aucune exception!):

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

La façon dont j'ai fait ceci est d'abord générer une entité Catégorie valide avec la clé d'entité.

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

Ou vous pouvez essayer de créer l'entité comme un talon pour sauver le coup à la DB:

Category myCategory = new Category{CategoryID = categoryIDToUse }; 

ajouter ensuite cette entité à l'ensemble des entités (CategorySet) sur le ObjectContext en utilisant la AttachTo méthode (vous pouvez vouloir vérifier si elle est déjà attachée). Vous pouvez ensuite ajouter la catégorie à votre entité utilisateur à l'aide de la méthode Add. Quelque chose comme ceci:

myUser.Categories.Add(myCategory); 

Appelez SaveChanges(). Cela a fonctionné pour moi.

+0

Peut-être que c'est un changement avec 4.0, mais il n'y a pas d'objet 'categoryset' sous myUser, mais il y a 'categories': myUser.Categories.Add (myCategory); Mais ce que j'ai déjà dans mon exemple de code ci-dessus. Je ne sais pas exactement ce que vous entendez par «générer une catégorie valide avec la clé d'entité». –

+0

J'utilise EF v1.0. J'ai mis à jour ma réponse. Par 'categoryset' je voulais dire quel que soit votre nom EntitySet pour les entités de Catégorie. Je vois que c'est 'Catégories' et j'ai mis à jour l'exemple de code. J'espère que ça aide. – DaveB

+0

Juste, malheureusement, c'est ce que j'ai fait avec les résultats indiqués ci-dessus. L'utilisation de: myCategory.Users.Add (myUser) AND/OR myUser.Categories.Add (myCategory) renvoie le 'un élément avec la même clé a déjà été ajouté' –

Questions connexes