AddOrUpdate fonctionne pas comme prévu et produit des doublons
Je suis à l'aide de Code-Première DBContext à base de EF5 de l'installation.
Dans DbMigrationsConfiguration.Seed
je suis en train de remplir DB par défaut des données factices. Pour accomplir cette tâche, j'utilise DbSet.AddOrUpdate
méthode.
Le code le plus simple pour illustrer mon objectif:
j = 0;
var cities = new[]
{
"Berlin",
"Vienna",
"London",
"Bristol",
"Rome",
"Stockholm",
"Oslo",
"Helsinki",
"Amsterdam",
"Dublin"
};
var cityObjects = new City[cities.Length];
foreach (string c in cities)
{
int id = r.NextDouble() > 0.5 ? 0 : 1;
var city = new City
{
Id = j,
Name = c,
Slug = c.ToLowerInvariant(),
Region = regions[id],
RegionId = regions[id].Id,
Reviewed = true
};
context.CitySet.AddOrUpdate(cc => cc.Id, city);
cityObjects[j] = city;
j++;
}
J'ai essayé d'utiliser/omettre Id
domaine ainsi que l'utilisation d' Id
/Slug
bien que la mise à jour du sélecteur.
quand Update-Database
est exécuté, Id
champ est ignoré et la valeur est générée automatiquement par le Serveur SQL de base de données et est rempli avec des doublons; Slug
sélecteur permet de doublons et sur les exécutions ultérieures produit des exceptions (Sequence contains more than one element
).
Est AddOrUpdate
méthode destinée à travailler de cette façon? Dois-je effectuer upsert à la main?
Vous devez vous connecter pour publier un commentaire.
Premier (pas encore de réponse),
AddOrUpdate
peut être appelée avec une multitude de nouveaux objets, de sorte que vous pouvez simplement créer un tableau de typeCity[]
et appelcontext.CitySet.AddOrUpdate(cc => cc.Id, cityArray);
une fois.(édité)
Deuxième,
AddOrUpdate
utilise l'identificateur de l'expression (cc => cc.Id
) pour trouver des villes avec le mêmeId
que celles précisées dans le tableau. Ces villes seront mis à jour. Les autres villes dans le tableau sera inséré, mais leurId
valeurs seront générés par la base de données, parce queId
est une colonne d'identité. Il ne peut pas être défini par une instruction insert. (Sauf si vous définissez l'Identité Insérer sur). Donc, lorsque vous utilisezAddOrUpdate
pour les tables avec des colonnes d'identité vous devez trouver un autre moyen pour identifier les enregistrements parce que les valeurs d'Id des enregistrements existants sont imprévisibles.Dans votre cas vous avez utilisé
Slug
comme identifiant pourAddOrUpdate
, qui doit être unique (comme par votre commentaire). Il n'est pas clair pour moi pourquoi ne pas mettre à jour les enregistrements existants avec correspondanceSlug
s.J'ai créé un petit test: ajouter ou mettre à jour une entité avec un Id (iedntity) et un nom unique:
Lorsque "Prod1" n'est pas encore là, il est inséré (en ignorant Id 999).
Si il l'est et
UnitPrice
est différent, il est mis à jour.En regardant les émissions de requêtes, je vois que EF est à la recherche d'un enregistrement unique par son nom:
Et suivant (lorsqu'une correspondance est trouvée et
UnitPrice
est différent)Cela montre que EF trouvé un enregistrement et utilise maintenant le champ clé pour faire la mise à jour.
J'espère que le fait de voir cet exemple de jeter un peu de lumière sur votre situation. Peut-être que vous devez suivre les instructions sql ainsi et voir si quelque chose d'inattendu se produit, là.
id=j
qui va de 0 à 9. Que vous avez été trompés par les mêmes noms de variables. Ensuite, je l'ai déjà mentionné l'effet de l'utilisation de Nom (dans mon cas, Slug, car il est vraiment unique) - c'est de laisser les dupliqué dans la DB. Le passage de tous les objets dans un tableau n'a pas renvoyé de tout progrès.p => new { p.ProductName, p.CategoryName }
@Jarviscontext.Set<TEntity>().AddOrUpdate(...)
vous avez de référence de la réelle DBSet.DbSet
. Si quelque chose se passe mal ici, il doit être quelque chose d'autre cause.