Comment puis-je utiliser EF pour ajouter plusieurs entités enfants à un objet lorsque l'enfant a une clé d'identité?
Nous utilisons EF5 et SQL Server 2012, les deux classes suivantes:
public class Question
{
public Question()
{
this.Answers = new List<Answer>();
}
public int QuestionId { get; set; }
public string Title { get; set; }
public virtual ICollection<Answer> Answers { get; set; }
}
public class Answer
{
public int AnswerId { get; set; }
public string Text { get; set; }
public int QuestionId { get; set; }
public virtual Question Question { get; set; }
}
Cartographie est comme suit:
public class AnswerMap : EntityTypeConfiguration<Answer>
{
public AnswerMap()
{
//Primary Key
this.HasKey(t => t.AnswerId);
//Identity
this.Property(t => t.AnswerId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Base de données DDL
CREATE TABLE Answer (
[AnswerId] INT IDENTITY (1, 1) NOT NULL,
[QuestionId] INT NOT NULL,
[Text] NVARCHAR(1000),
CONSTRAINT [PK_Answer] PRIMARY KEY CLUSTERED ([AnswerId] ASC)
)";
Voici les résultats de ce que j'ai essayé:
Ce qui fonctionne pour un enfant:
var a = new Answer{
Text = "AA",
QuestionId = 14
};
question.Answers.Add(a);
_uow.Questions.Update(question);
_uow.Commit();
Cela ne fonctionne pas pour plus d'un enfant:
Erreur: Un objet avec la même clé existe déjà dans le Vousmanager. Le Vousmanager ne peut suivre plusieurs objets avec la même clé.
var a = new Answer{
AnswerId = 0,
Text = "AAA",
QuestionId = 14
};
var b = new Answer {
AnswerId = 0,
Text = "BBB",
QuestionId = 14
};
question.Answers.Add(a);
question.Answers.Add(b);
_uow.Questions.Update(question);
_uow.Commit();
Cela ne fonctionne pas pour plus d'un enfant:
Il crée AnswerID 1000 et 1001, mais je veux une nouvelle carte d'identité pour être créé par la base de données.
var a = new Answer{
AnswerId = 1000,
Text = "AAA",
QuestionId = 14
};
var b = new Answer {
AnswerId = 1001,
Text = "BBB",
QuestionId = 14
};
question.Answers.Add(a);
question.Answers.Add(b);
_uow.Questions.Update(question);
_uow.Commit();
Ne fonctionne pas:
D'erreur du compilateur. Ne peut pas convertir la valeur null pour int
var a = new Answer{
AnswerId = null,
Text = "AAA",
QuestionId = 14
};
var b = new Answer
{
AnswerId = null,
Text = "BBB",
QuestionId = 14
};
question.Answers.Add(a);
question.Answers.Add(b);
_uow.Questions.Update(question);
_uow.Commit();
Ne fonctionne pas:
Vousmanager ne peut suivre plusieurs objets avec la même clé.
var a = new Answer{
Text = "AAA",
QuestionId = 14
};
var b = new Answer
{
Text = "BBB",
QuestionId = 14
};
question.Answers.Add(a);
question.Answers.Add(b);
_uow.Questions.Update(question);
_uow.Commit();
Dans mon application j'ai un ou de plusieurs nouveaux Réponse objets générés sur le client, puis ceux-ci sont envoyés au serveur. Au-dessus de je suis la simulation de ce qui va se passer sans ajouter le client sur la question. Notez que l'ajout de toutes les Réponses à la Question de l'objet se fait sur le client, puis vient dans une chaîne JSON pour le serveur. Il est alors désérialisé à une Question de l'Objet comme ceci:
public HttpResponseMessage PutQuestion(int id, Question question) {
_uow.Questions.Update(question);
_uow.Commit();
Je veux que chacun de Répondre à créer des objets avec un new identity ID
pour qu'elles soient ajoutées à la Question de l'objet et pour la Question de l'objet à être retourné de la manière normale.
Je ne sais pas comment cela peut être fait. Tous mes tests simples jusqu'à présent ne fonctionnent pas. Veuillez noter que ceci est une variation sur une question précédente par notre membre du groupe qui l'était moins, et que je suis en train de fermer. Cette question est, je l'espère, de plus en plus clair.
Notes:
Ici est la façon dont la mise à jour est codé:
public virtual void Update(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State == EntityState.Detached)
{
DbSet.Attach(entity);
}
dbEntityEntry.State = EntityState.Modified;
}
source d'informationauteur Melina
Vous devez vous connecter pour publier un commentaire.
Avez-vous dit que vous ajoutez
a
deux fois...?!Généralement, pour ajouter des éléments qui leur carte d'identité, vous devez ignorer le réglage de l'id. Vous devez également ajouter le
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
attribuer à ces Id:Et ajouter des données comme ceci:
J'ai couru dans la même identité "limitation". Il s'avère que si vous ajoutez un parent et les enfants, l'EF peut gérer le fait que le parent et les enfants sont tous ajoutés ensemble. Vous rencontrez des problèmes lorsque vous mettez à Jour le parent et insérez les deux enfants en même temps. Si vous fixez le parent, EF va automatiquement chercher les deux enfants et les joindre si vous le voulez ou pas. Depuis, nous le voulons pour générer automatiquement l'Id, on ne peut pas définir la clé primaire des enfants. Cependant, l'EF ne peut pas gérer les éléments avec la même clé Primaire lorsque le parent est une mise à Jour et explose puisque les deux ont la même PK de 0 pour les deux enfants.
Le seul moyen que j'ai trouvé, c'est de définir manuellement l'id des enfants à des numéros différents. J'ai l'habitude de définir le premier enfant de l'Id de -1, -2 pour le deuxième enfant, et ainsi de suite. Ce sera la cause de EF pour sauver les enfants et la clé sera automatiquement mis à jour en raison de l'Identité en cours d'exécution sur la base de données car -1 et -2 ne sont pas valables les valeurs d'identité.
Cependant, cela va causer une grande douleur si vous avez un niveau 3 ou au-delà. Non seulement vous devez mettre à jour PK à chaque enfant, mais vous devrez alors mettre à jour le FK sur l'un de ses enfants pour cette nouvelle -1 ou -2 valeur. Sinon, la sauvegarde échoue à nouveau!
La seule autre option que je vois est vraiment juste à insérer un enfant à un temps et économiser de sorte que le contexte n'est pas affaire avec plus d'un objet avec la même PK, mais ce genre de défaites le but d'un ORM...
Si vous avez bien déclaré l'Id comme Clé et comme DBGenerated identité.
Ensuite, EF vous permettra AJOUTER beaucoup de ces le contexte avant de l'enregistrer.
Vous ne pouvez PAS ATTACHER les éléments avec la même clé.
Joindre est destinée pour les données en mode hors connexion, les mettre dans le contexte, définir son état et d'enregistrer le type de scénarios.
Vous avez utilisé la Même instance à deux reprises et avec les objectifs EF de suivi par défaut causé un désordre.
Ou en quelque sorte utilisé JOINDRE deux fois. Assurez-vous que vous gérez vos instances proprement.*
par exemple
Un juste essayé un Test simple pour vérifier qu'il fonctionne (ef5)
edit: À la demande, l'ajout d'enregistrer Respository modèle, l'échantillon de Base, la gestion d'erreur supprimé
....
Essayez ces choses:
Create()
méthode deDbSet
Answers
collection de votreContext
Vous avez défini le
QuestionId
de manière appropriée pour EF réaliser la relation. Aussi, ne définissez pas explicitement AnswerId à zéro.Vous pouvez avoir besoin de faire un appel à
_uow.ChangeTracker.DetectChanges()
si vous prévoyez sur l'interrogation de laAnswers
collection deQuestion
14