12
votes

Comment 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 virtual void Update(T entity)
{
    DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
    if (dbEntityEntry.State == EntityState.Detached)
    {
        DbSet.Attach(entity);
    }  
    dbEntityEntry.State = EntityState.Modified;
}


2 commentaires

Pourquoi ajoutez-vous une réponse deux fois?


Erreur de syntaxe - Fixe maintenant. Merci d'avoir souligné cela. Le code actuel tente d'ajouter une variable "A", puis "B".


5 Réponses :


0
votes

Essayez ces choses:

  • Utilisez la méthode CREATE () de DBSet
  • ajoutez les nouvelles instances à la réponses Collection de votre contexte

    Vous avez défini le questionnaire de manière appropriée pour EF pour réaliser la relation. En outre, ne définissez pas explicitement réponse à zéro. xxx

    Vous devrez peut-être apporter un appel à _uow.changetracker.detectchanges () si vous planifiez Sur interrogation des réponses Collection de Question 14


1 commentaires

Le problème avec c'est que je suis ici simulant ce qui se passe sur le client où les deux objets de réponse ont déjà été ajoutés et apparaissent dans le cadre de l'objet de la question. L'objet de la question complète vient en tant que JSON sur le serveur. Pour cette raison, je ne peux d'abord pas créer la réponse et puis les ajouter de cette manière. De plus, je pensais que tout le point de EF était que cela devrait être capable de faire face à cela car il semble que une chose assez commune de faire. Merci pour votre aide / conseil.



1
votes

Avez-vous mentionné que vous ajoutez A code> deux fois ... ?!

var a = new Answer{
    Text = "AAA",
    QuestionId = 14
};

var b = new Answer
{
    Text = "BBB",
    QuestionId = 14
};

dbContext.Answers.Add(a);
dbContext.Answers.Add(b);

dbContext.SaveChanges();

// ...


7 commentaires

Désolé, c'était une erreur de frappe que j'ai corrigée. Je fais déjà ce que vous suggérez avec la cartographie de l'API fluide Voir le code ci-dessus. : cela.property (t => t.answerid) .hasdatabaseGeneratedoption (génération de la base de donnéesOptionOdentité);


AMIN - Mon problème est que tout le travail est effectué sur le client. Les objets de réponse sont ajoutés là-bas à l'objet de la question. Lorsque l'utilisateur clique sur Enregistrer, ceci est transmis sur le serveur en tant qu'objet de la question complète avec les nouvelles réponses. J'aurais pensé que EF aurait pu gérer la mise à jour d'une question avec de nouveaux objets de réponse. Peut-être que ce n'est pas possible dans EF, mais cela semble être un besoin fondamental.


@Alan si vous voulez les mettre à jour comme celui-ci _uow.questions.update (question); Vous devez ajouter toutes les nouvelles et nouvelles réponses à la question, puis mettez-la à la mise à jour ...


@Amin - Comment pouvons-nous choisir les objets de réponse de l'objet de la question? Mettre à jour la question puis les ajouter à nouveau? Devrions-nous les ajouter à un par un pour surmonter le problème avec la génération de valeurs de clé d'identité pour les réponses.


@Melina qui est possible, cependant, cela vous conduira à une autre erreur logique: vous aurez des réponses en double (dans le texte) mais avec des identifiants différents. Dites-moi ce que vous essayez de faire. Peut-être que je pourrais vous montrer une autre façon ...


Nos utilisateurs ajoutent des objets de réponse à un objet de questions sur le client. Lorsqu'ils cliquent sur Enregistrer l'objet de la question avec 0 ou plusieurs nouvelles réponses sont transmises au serveur. Nous mettons ensuite à jour l'objet de la question et, espérons-le, les nouvelles réponses avec des répondeurs corrects générés par la base de données.


@Melina Si vous voulez une manière complète, fiable et sans erreur, vous avez plusieurs œuvres à faire. Voir Ce pour vous montrer comment. J'ai aussi des réponses sur cette zone comme Ce



0
votes

Si vous avez correctement déclaré l'ID comme clé et comme étant une identité de DBGenerated. Ensuite, ef vous permettra ajouter beaucoup d'entre eux au contexte avant d'économiser. Vous ne pouvez pas attacher d'éléments avec la même clé . L'attachement est conçu pour les données hors connexion, mettre en contexte, définir son état et enregistrer des scénarios de type.

Vous avez utilisé la même instance deux fois et avec le suivi EF par défaut a provoqué un gâchis. Ou d'une manière ou d'une autre, attachez deux fois. Assurez-vous de gérer vos instances proprement. *

par exemple xxx

A vient d'essayer un test simple pour vérifier que cela fonctionne (dans ef5 ) xxx

EDIT: sur demande, ajout de modèle de rémunération, échantillon de base, manipulation d'erreur supprimé xxx

.... xxx


6 commentaires

Phil - J'ai les déclarations pour la réponse à mon code ci-dessus, mais votre exemple est très différent de celui des miens. J'ai un objet parent que j'ajoute les enfants aussi, puis je fais les SAVECHANGES. Si je suis quel que soit votre exemple, cela fonctionne également bien.


D'accord, l'extrait d'être convivial est ok d'instances. Si tel est vraiment le code. qu'est-ce que _uow.Questions.update (question); faire ? Je suppose aussi que commettez simplement appelle des savechanges. Alors la seule différence évidente est que j'utilise toujours virtuel sur les accessoires de Poco


La mise à jour est la suivante: Mise à jour du vide virtuel (Public Virtual Void (entité) {dbentityentry dbentityenterry = dbcontext.Entry (entité); if (dbenttityenterry.state == entitystate.detached) {dbset.attach (entité); } dbentityenterry.state = entitystate.Modifiée; } Désolé pour la façon dont il s'affiche dans cette zone de commentaire. Oui commettre appelle Savechanges. Dans quelle propriété POCO parlez-vous. Je pensais que tous ceux qui avaient besoin de cela ont été déclarés virtuels dans mon code.


Là le problème ... Joindre que vous ne pouvez pas attacher la même clé deux fois. Réponse de mise à jour malade pour souligner le point


Merci Phil. J'ai ajouté mon code de mise à jour à la question. Y a-t-il une autre mise à jour générique que je pouvais ajouter au répétant et à utiliser? Si vous montrez une réponse, pouvez-vous faire une suggestion sur la façon dont je pourrais recoder merci.


@Manks Phil - Je regarderais dans cette situation et, en même temps, regardez d'autres alternatives.



7
votes

J'ai également rencontré la même identité "limitation". Il s'avère que si vous ajoutez un parent et des enfants, EF peut gérer le fait que les parents et les enfants sont tous ajoutés ensemble. Vous rencontrez des problèmes lorsque vous mettez à jour le parent et insérez deux enfants en même temps. Si vous attachez le parent, EF ramassera automatiquement ces deux enfants et les attacher à ce que vous le souhaitez ou non. Puisque nous voulons que cela génère automatiquement l'ID, nous ne définirons pas la clé primaire des enfants. Cependant, EF ne peut pas gérer des éléments avec la même clé primaire lorsque le parent est une mise à jour et souffle, car les deux ont le même PK de 0 pour les deux enfants.

Le seul moyen que j'ai trouvé autour de cela est de définir manuellement les identifiants des enfants à différents nombres. Je fixe généralement le premier ID de l'enfant à -1, puis -2 pour le deuxième enfant, etc. Cela entraînera une économie d'EF pour sauver les enfants et la clé sera automatiquement mise à jour en raison de l'exécution de l'identité de la base de données car -1 et -2 ne sont pas des valeurs d'identité valides.

Cependant, cela causera une grande douleur si vous avez un 3ème niveau ou au-delà. Non seulement vous devez mettre à jour ce PK sur chaque enfant, mais vous devez alors mettre à jour le FK sur l'un de ses enfants à cette nouvelle valeur de -1 ou -2. Sinon, l'enregistrement échouera à nouveau!

La seule autre option que je vois est vraiment juste pour insérer un enfant à la fois et appeler économisez pour que le contexte ne traite pas de plus d'un objet avec le même PK, mais ce type de défaite le but d'un orj. ..


5 commentaires

Ajout de [DatabaseGenerateDatribute (génération de la base de donnéesOption.Identifity)] Comme suggéré par @Aminsaghi n'a pas fonctionné pour moi, mais cela a fait. Merci!


À partir de EF 6.1.2 (peut-être plus tôt), ce n'est plus un problème. Il semble fonctionner comme prévu maintenant! :)


En fait, si vous parcourez l'entité d'entité et ajoutez tous les nouveaux articles avant de joindre les mises à jour, cela fonctionne également.


Je sais que ce fil est de près de trois ans, mais je voulais juste dire que j'ai rencontré le même problème que @Daniellorenz décrit lors de l'utilisation de EF 6.1.3. La seule façon dont je me suis arrangé consiste à insérer un enfant à la fois


Une autre solution à cet égard est de ne rien ajouter d'abord toutes les nouvelles entités. Une fois que tous les ajouts sont terminés, vous pouvez revenir en arrière et attacher tous les autres éléments après. C'est ce que j'ai fini par faire pour éviter d'assigner des PC négatives tout le temps.



0
votes

Alors que je traversais le même problème. Alors pensé soumettre ma solution. Il sera utile pour les autres personnes qui seront recherchées - xxx


0 commentaires