Comment puis-je obtenir l'ID de l'entité insérée dans le cadre Entity? [fermé]

611

J'ai un problème avec Entity Framework dans Asp.net. Je veux obtenir la valeur Id chaque fois que j'ajoute un objet à la base de données. Comment puis-je faire ceci?

ahmet
la source
16
La réponse de Ladislav Mrnka ci-dessous est la bonne réponse et doit être acceptée comme telle.
CShark
3
L'OP n'a posté qu'une seule fois avec son compte, cette question pour être plus précise. Cela lui a accordé près de 2k de réputation (!), La réponse n'est pas marquée comme acceptée car le compte est abandonné depuis ce jour.
MurariAlex
1
Si vous avez juste besoin de l'ID pour l'utiliser dans une relation de clé étrangère, vous pouvez envisager de définir simplement la propriété de navigation de votre entité dépendante sur l'entité ajoutée précédemment. De cette façon, vous n'avez pas à vous soucier d'appeler SaveChangestout de suite juste pour obtenir l'identifiant. Plus de lecture ici .
B12Toaster
Pour Entity Framework Core 3.0, ajoutez le paramètre acceptAllChangesOnSuccess comme true: wait _context.SaveChangesAsync (true);
Mike

Réponses:

1006

C'est assez simple. Si vous utilisez des ID générés par la base de données (comme IDENTITYdans MS SQL), il vous suffit d'ajouter une entité à ObjectSetet SaveChangessur les éléments associés ObjectContext. Idsera automatiquement rempli pour vous:

using (var context = new MyContext())
{
  context.MyEntities.Add(myNewObject);
  context.SaveChanges();

  int id = myNewObject.Id; // Yes it's here
}

Le framework d'entité suit par défaut chacun INSERTavec SELECT SCOPE_IDENTITY()quand les Ids générés automatiquement sont utilisés.

Ladislav Mrnka
la source
34
Vous posez donc une mauvaise question. Si vous rencontrez un problème avec l'exception, vous devez poser une question indiquant votre exception (et l'exception interne) et l'extrait de code à l'origine de cette erreur.
Ladislav Mrnka
3
Assurez-vous que l'entité que vous ajoutez est une entité valide, par exemple, tout ce qui a une restriction de base de données "non nulle" doit être rempli, etc.
fran
4
@LadislavMrnka: Qu'en est-il des propriétés de navigation de l'objet nouvellement créé? Ils ne semblent pas être remplis automatiquement après avoir enregistré les modifications.
Isaac Kleinman
4
Prenons le scénario suivant: table1 est censé générer une identité @@ pour l'utiliser dans table2. Table1 et table2 sont supposées être dans la même transaction, par exemple une opération SaveChange doit enregistrer les données de la table. L'identité @@ ne sera générée que si un «SaveChanges» est invoqué. comment faire face à cette situation?
Arash
7
@Djeroen: Si vous utilisez l'ID généré par la base de données, vous devez d'abord insérer ces objets dans la base de données. Si vous devez avoir des identifiants avant l'insertion, vous devez créer votre propre logique pour obtenir des identifiants uniques avant l'insertion des données et ne pas utiliser la colonne d'identité dans la base de données.
Ladislav Mrnka
124

J'avais utilisé la réponse de Ladislav Mrnka pour récupérer avec succès les identifiants lors de l'utilisation de l'Entity Framework, mais je poste ici parce que je l'avais mal utilisé (c'est-à-dire si je ne l'utilisais pas) et pensais publier mes résultats ici dans les gens cherchent à "résoudre" le problème que j'avais.

Considérons un objet Order qui a une relation de clé étrangère avec le client. Quand j'ai ajouté un nouveau client et une nouvelle commande en même temps, je faisais quelque chose comme ça;

var customer = new Customer(); //no Id yet;
var order = new Order(); //requires Customer.Id to link it to customer;
context.Customers.Add(customer);
context.SaveChanges();//this generates the Id for customer
order.CustomerId = customer.Id;//finally I can set the Id

Cependant, dans mon cas, cela n'était pas nécessaire car j'avais une relation de clé étrangère entre customer.Id et order.CustomerId

Tout ce que j'avais à faire était ceci;

var customer = new Customer(); //no Id yet;
var order = new Order{Customer = customer}; 
context.SaveChanges();//adds customer.Id to customer and the correct CustomerId to order

Maintenant, lorsque j'enregistre les modifications, l'ID généré pour le client est également ajouté à la commande. Je n'ai pas besoin des étapes supplémentaires

Je suis conscient que cela ne répond pas à la question d'origine, mais j'ai pensé que cela pourrait aider les développeurs qui sont nouveaux dans EF à sur-utiliser la réponse la plus votée pour quelque chose qui n'est peut-être pas nécessaire.

Cela signifie également que les mises à jour se terminent en une seule transaction, évitant potentiellement les données orphin (soit toutes les mises à jour sont terminées, soit aucune ne le fait).

mark_h
la source
8
Merci ! Conseil de bonne pratique IMPORTANT: var order = new Order {Customer = customer}; Cela montre la puissance d'Entity Framework pour attribuer un objet associé et l'ID sera automatiquement mis à jour.
LA Guy 88
Merci pour ces informations supplémentaires à la réponse. A été très utile pour enregistrer un aller-retour DB lors de l'utilisation d'EF.
Prasad Korhale
Merci beaucoup pour cela. Ceci est exactement ce que je cherchais. Je pensais juste qu'il pourrait y avoir un meilleur moyen que d'appeler "SaveChanges" deux fois
Josh
1
Veuillez également mentionner dans votre réponse (de préférence en caractères gras) que cela résout un comportement de transaction. Si l'un des objets n'a pas pu être ajouté, une partie de la transaction échouera. Par exemple, ajouter une personne et un étudiant. La personne réussit et l'élève échoue. Maintenant, la personne est redondante. Merci pour cette excellente solution!
Imran Faruqi
32

Vous devez recharger l'entité après avoir enregistré les modifications. Parce qu'il a été modifié par un déclencheur de base de données qui ne peut pas être suivi par EF. Nous devons donc recharger à nouveau l'entité à partir de la base de données,

db.Entry(MyNewObject).GetDatabaseValues();

alors

int id = myNewObject.Id;

Regardez la réponse de @jayantha dans la question ci-dessous:

Comment puis-je obtenir l'ID de l'entité insérée dans le cadre Entity lors de l'utilisation de defaultValue?

La recherche de la réponse @christian dans la question ci-dessous peut également aider:

Entity Framework Actualiser le contexte?

QMaster
la source
2
Salut, quand j'aime ça, j'obtiens l'erreur de compilation qui dit: ne peut pas résoudre les propriétés par exemple Id ou Name, pouvez-vous m'aider s'il vous plaît?
Morteza Azizi
1
@MortezaAzizi Cela semble être une erreur de problème de propriété non géré ou nul, mais pouvez-vous s'il vous plaît expliquer davantage ou écrire un extrait de code?
QMaster
3
Cela ne devrait pas avoir à faire .GetDatabaseValues();si vous venez d'enregistrer votre modèle dans la base de données. L'ID doit se repeupler automatiquement sur le modèle.
vapcguy
3
@QMaster Sauf que EF est également capable (et exécute) la même instruction SQL et remplit l'ID de votre objet. Sinon, comment peut-il enregistrer plusieurs objets dépendants en même temps? Comment pourrait-il le faire GetDatabaseValues()s'il ne connaît pas l'ID de l'objet à rechercher dans la base de données?
krillgar
2
@vapcguy je vois. Merci pour vos attentions. Je vérifierai cela dans les deux versions d'EF ASAP.
QMaster
16

Veuillez vous référer à ce lien.

http://www.ladislavmrnka.com/2011/03/the-bug-in-storegeneratedpattern-fixed-in-vs-2010-sp1/

Vous devez définir la propriété de StoreGeneratedPattern sur l'identité, puis essayer votre propre code.

Sinon, vous pouvez également l'utiliser.

using (var context = new MyContext())
{
  context.MyEntities.AddObject(myNewObject);
  context.SaveChanges();

  int id = myNewObject.Id; // Your Identity column ID
}
Azhar Mansuri
la source
7
Identique à la réponse la plus votée.
Lewis86
2
StoreGeneratedPatternétait la pièce manquante pour moi.
BurnsBA
1
C'est la voie à suivre lorsque vous travaillez avec ORACLE et ON-Insert Trigger,
Karl
lien rompu - domaine parqué
t.durden
Salut avec Oracle, je devais définir StoreGeneratedPattern dans Entity - allez dans le visualiseur de modèle, trouvez votre table et PK, sélectionnez la propriété StoreGeneratedPattern et définissez sur Identity. Cela fonctionne comme l'indique la réponse ci-dessus. C'est pour le cas où vous avez un déclencheur qui remplit votre PK à partir d'une séquence en insertion.
Rob
15

L'objet que vous enregistrez doit avoir une valeur correcte Idaprès avoir propagé les modifications dans la base de données.

Snowbear
la source
27
avez-vous vu l'exception intérieure? ;-)
Snowbear
6

Vous ne pouvez obtenir l'ID qu'après avoir enregistré, au lieu de cela, vous pouvez créer un nouveau Guid et l'attribuer avant de l'enregistrer.

Vaduganathan Pillappan
la source
4

Je tombe sur une situation où j'ai besoin d'insérer les données dans la base de données et d'exiger simultanément l'ID principal en utilisant le cadre d'entité. Solution :

long id;
IGenericQueryRepository<myentityclass, Entityname> InfoBase = null;
try
 {
    InfoBase = new GenericQueryRepository<myentityclass, Entityname>();
    InfoBase.Add(generalinfo);
    InfoBase.Context.SaveChanges();
    id = entityclassobj.ID;
    return id;
 }
M. Kunal
la source
4

Toutes les réponses sont très bien adaptées à leurs propres scénarios, ce que j'ai fait différemment, c'est que j'ai attribué l'int PK directement à partir de l'objet (TEntity) que Add () a renvoyé à une variable int comme celle-ci;

using (Entities entities = new Entities())
{
      int employeeId = entities.Employee.Add(new Employee
                        {
                            EmployeeName = employeeComplexModel.EmployeeName,
                            EmployeeCreatedDate = DateTime.Now,
                            EmployeeUpdatedDate = DateTime.Now,
                            EmployeeStatus = true
                        }).EmployeeId;

      //...use id for other work
}

donc au lieu de créer un tout nouvel objet, vous prenez juste ce que vous voulez :)

EDIT Pour M. @GertArnold:

entrez la description de l'image ici

IteratioN7T
la source
3
Il n'est pas vraiment utile d'ajouter une méthode non divulguée pour attribuer un ID. Ce n'est même pas lié à Entity Framework.
Gert Arnold,
1
@GertArnold .. j'ai eu la même question que l'OP j'ai trouvé les réponses et en ai fait une déclaration sur une seule ligne, et je n'ai jamais entendu parler du terme méthode non divulguée soin d'expliquer?
IteratioN7T
3
Cela signifie simplement que vous ne montrez pas (ne divulguez) pas tout ce que vous faites. Peut-être que ce n'est pas clairement décrit, je ne sais pas. Ce que je sais, c'est que Add(si c'est le cas DbSet.Add) n'attribue pas de valeur par magie EmployeeId.
Gert Arnold
3
Pas sans SaveChanges. Impossible. À moins que vous n'ayez un autre processus à attribuer EmployeeId, par exemple dans Employeele constructeur de. OU vous utilisez le noyau EF ForSqlServerUseSequenceHiLo. Quoi qu'il en soit, vous ne donnez pas l'image entière.
Gert Arnold,
3
Ma dernière remarque sera: ce n'est pas un comportement EF standard. Vous devez donner plus de détails sur votre environnement. Version EF, marque et version de la base de données, classe Employee, ses détails de mappage.
Gert Arnold,
3
Repository.addorupdate(entity, entity.id);
Repository.savechanges();
Var id = entity.id;

Cela fonctionnera.

Saket Choubey
la source
4
Le référentiel n'est pas responsable de l'enregistrement des modifications dans la base de données. C'est le travail de UnitOfWork.
tchelidze
5
De plus, ce n'est absolument pas clair Repository. Et "cela fonctionnera" est une explication!.
Gert Arnold,
2

Il existe deux stratégies:

  1. Utiliser une base de données générée ID( intou GUID)

    Les inconvénients:

    Vous devez effectuer SaveChanges()pour obtenir les IDentités juste enregistrées.

    Avantages:

    Peut utiliser l' intidentité.

  2. Utiliser le client généré ID- GUID uniquement.

    Avantages: Minification des SaveChangesopérations. Capable d'insérer un grand graphique de nouveaux objets par opération.

    Les inconvénients:

    Autorisé uniquement pour GUID

Vladislav Furdak
la source
1

Lorsque vous utilisez d'abord le code EF 6.x

    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

et initialiser une table de base de données, il mettra un

(newsequentialid())

à l'intérieur des propriétés de la table sous l'en-tête Valeur par défaut ou Liaison, permettant à l'ID d'être rempli lors de son insertion.

Le problème est que si vous créez une table et ajoutez le

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]

partie plus tard, les futures bases de données de mise à jour ne rajouteront pas le (newsequentialid ())

Pour corriger la bonne façon, vous devez effacer la migration, supprimer la base de données et re-migrer ... ou vous pouvez simplement ajouter (newsequentialid ()) dans le concepteur de table.

Jeff Li
la source
Pouvez-vous expliquer où va newsequentialid ()? J'ai déjà des modèles de base de données créés à la main, n'utilisant pas le code EF en premier, et il ne remplit pas l'identifiant car ce n'est pas ma clé primaire. J'adorerais trouver une solution pour cela.
Josh
1
@josh En supposant que le code est d'abord de type Guid, cliquez avec le bouton droit sur votre table dans Sql Server Management Studio, cliquez sur la colonne Id et sous l'onglet Propriétés de la colonne, à l'intérieur (Général), vous verrez Valeur par défaut ou Liaison. Si vous créez des tables de base de données à la main, reportez-vous à NewSequentialId ou NewId . Le cas d'utilisation général est quelque chose commewhen -column- is NULL, then NEWID()
Jeff Li