Como posso obter o ID da entidade inserida na estrutura da entidade? [fechadas]

611

Eu tenho um problema com o Entity Framework no Asp.net. Quero obter o valor do ID sempre que adiciono um objeto ao banco de dados. Como posso fazer isso?

ahmet
fonte
16
A resposta de Ladislav Mrnka abaixo é a resposta correta e deve ser aceita como tal.
CShark 17/05/19
3
O OP postou apenas uma vez com sua conta, esta questão para ser mais específica. Isso concedeu a ele quase 2k de reputação (!), A resposta não é marcada como aceita porque a conta é abandonada desde aquele dia.
MurariAlex
1
Se você apenas precisar do ID para usá-lo em um relacionamento de chave estrangeira, considere configurar a propriedade de navegação da sua entidade dependente para a entidade adicionada anteriormente. Dessa forma, você não precisa se preocupar em ligar SaveChangesimediatamente apenas para obter o ID. Leia mais aqui .
B12Toaster
Para o Entity Framework Core 3.0, adicione o parâmetro acceptAllChangesOnSuccess como true: waitit _context.SaveChangesAsync (true);
Mike

Respostas:

1006

É bem fácil Se você estiver usando DB gerado Ids (como IDENTITYem MS SQL), você só precisa adicionar entidade ObjectSete SaveChangesna relacionado ObjectContext. Idserá preenchido automaticamente para você:

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

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

A estrutura da entidade, por padrão, segue cada INSERTuma delas SELECT SCOPE_IDENTITY()quando Ids gerados automaticamente são usados.

Ladislav Mrnka
fonte
34
Então você está fazendo uma pergunta errada. Se você tiver um problema com exceção, faça a pergunta que mostra sua exceção (e exceção interna) e o snippet de código que está causando esse erro.
Ladislav Mrnka 6/03/11
3
. Certifique-se de que a entidade que você está adicionando é uma entidade válida por exemplo, qualquer coisa com uma restrição de banco de dados de "não nulo" deve ser preenchido etc.
fran
4
@LadislavMrnka: E as propriedades de navegação do objeto recém-criado? Eles não parecem ser preenchidos automaticamente após salvar as alterações.
Isaac Kleinman 11/11
4
Vamos considerar o seguinte cenário: a tabela1 deve gerar uma identidade @@ para usá-la na tabela2. As tabelas 1 e 2 devem estar na mesma transação, por exemplo, uma operação SaveChange deve salvar os dados de ambas as tabelas. A identidade @@ não será gerada a menos que um 'SaveChanges' seja chamado. como podemos resolver esta situação?
Arash 23/11
7
@ Djeroen: Se você usar o ID gerado pelo banco de dados, primeiro precisará inserir esses objetos no banco de dados. Se você precisar ter IDs antes da inserção, deverá criar sua própria lógica para obter IDs exclusivos antes da inserção dos dados e não usar a coluna de identidade no banco de dados.
Ladislav Mrnka
124

Eu estava usando a resposta de Ladislav Mrnka para recuperar IDs com sucesso ao usar o Entity Framework, no entanto, estou postando aqui porque estava com falta de usá-lo (ou seja, onde não era necessário) e pensei em publicar minhas descobertas aqui em caso as pessoas estejam procurando "resolver" o problema que tive.

Considere um objeto Pedido que tenha um relacionamento de chave estrangeira com o Cliente. Quando adicionei um novo cliente e um novo pedido ao mesmo tempo, estava fazendo algo parecido com isto;

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

No entanto, no meu caso, isso não foi necessário porque eu tinha um relacionamento de chave estrangeira entre customer.Id e order.CustomerId

Tudo que eu tinha que fazer era isso;

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

Agora, quando eu salvo as alterações, o ID gerado para o cliente também é adicionado ao pedido. Não preciso das etapas adicionais

Estou ciente de que isso não responde à pergunta original, mas achei que poderia ajudar os desenvolvedores novatos na EF a usarem excessivamente a resposta mais votada para algo que pode não ser necessário.

Isso também significa que as atualizações são concluídas em uma única transação, evitando potencialmente os dados do orphin (todas as atualizações são concluídas ou nenhuma).

mark_h
fonte
8
Obrigado ! Dica importante sobre as melhores práticas: var order = new Order {Customer = customer}; Isso mostra o poder do Entity Framework para atribuir objetos relacionados e o ID será atualizado automaticamente.
LA Guy 88
Obrigado por esta informação adicional para a resposta. Foi muito útil para salvar uma ida e volta ao banco de dados ao usar o EF.
Prasad Korhale
Muito obrigado por isso. Era exatamente isso que eu estava procurando. Eu só acreditava que poderia haver uma maneira melhor do que chamar "SaveChanges" duas vezes
Josh
1
Mencione também em sua resposta (de preferência em negrito) que isso resolve o comportamento de uma transação. Se um dos objetos não conseguir adicionar, parte da transação não será bem-sucedida. Por exemplo, adicionando pessoa e aluno. A pessoa tem sucesso e o aluno falha. Agora a pessoa é redundante. Obrigado por esta ótima solução!
Imran Faruqi
32

Você precisa recarregar a entidade após salvar as alterações. Porque foi alterado por um gatilho de banco de dados que não pode ser rastreado pelo EF. Portanto, precisamos recarregar a entidade novamente do banco de dados,

db.Entry(MyNewObject).GetDatabaseValues();

Então

int id = myNewObject.Id;

Veja a resposta @jayantha na pergunta abaixo:

Como posso obter o ID da entidade inserida na estrutura da entidade ao usar o defaultValue?

Procurar a resposta @christian na pergunta abaixo também pode ajudar:

Contexto de atualização do Entity Framework?

QMaster
fonte
2
Olá, quando faço isso, recebo o erro de compilação que diz: não é possível resolver as propriedades, por exemplo, ID ou nome, você pode me ajudar, por favor?
Morteza Azizi
1
@MortezaAzizi Parece ser um erro de problema de propriedade não tratado ou nulo, mas você pode explicar mais ou escrever algum trecho de código?
QMaster
3
Não deveria ter que fazer .GetDatabaseValues();se você acabou de salvar seu modelo no banco de dados. O ID deve preencher novamente o modelo automaticamente.
vapcguy
3
@QMaster Exceto que a EF também é capaz de (e executa) a mesma instrução SQL e preenche o ID do seu objeto. Caso contrário, como ele pode salvar vários objetos dependentes ao mesmo tempo? Como seria possível GetDatabaseValues()se não souber o ID do objeto a ser procurado no banco de dados?
precisa saber é o seguinte
2
@vapcguy eu vejo. Obrigado por suas atenções. Vou verificar isso nas duas versões do EF o mais rápido possível.
QMaster 27/09/18
16

Por favor, consulte este link.

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

Você deve definir a propriedade StoreGeneratedPattern como identidade e, em seguida, tentar seu próprio código.

Ou então você também pode usar isso.

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

  int id = myNewObject.Id; // Your Identity column ID
}
Azhar Mansuri
fonte
7
O mesmo que a resposta mais votada.
Lewis86
2
StoreGeneratedPatternfoi a peça que faltava para mim.
BurnsBA
1
Esse é o caminho a percorrer quando se trabalha com Oracle e ON-Insert Trigger,
Karl
link está quebrado - domínio estacionado
t.durden 5/09/19
Olá, com o Oracle, tive que definir o StoreGeneratedPattern na Entity - vá para o visualizador de modelos, encontre sua tabela e PK, selecione a propriedade StoreGeneratedPattern e defina Identity. Funciona como a resposta acima indica. É para o caso em que você tem um gatilho que preenche seu PK a partir de uma sequência na inserção.
Rob
15

O objeto que você está salvando deve ter um correto Idapós a propagação das alterações no banco de dados.

Urso de neve
fonte
27
você viu a exceção interior? ;-)
Snowbear
6

Você pode obter o ID apenas após salvar, em vez disso, pode criar um novo Guid e atribuir antes de salvar.

Vaduganathan Pillappan
fonte
4

Me deparei com uma situação em que preciso inserir os dados no banco de dados e, simultaneamente, exigir o ID primário usando a estrutura da entidade. Solução:

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

Todas as respostas são muito adequadas para seus próprios cenários, o que fiz de diferente é que atribuai o PK int diretamente do objeto (TEntity) que Add () retornou a uma variável int como esta;

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
}

então, em vez de criar um novo objeto inteiro, basta pegar o que deseja :)

EDIT Para Mr. @GertArnold:

insira a descrição da imagem aqui

IteratioN7T
fonte
3
Não é realmente útil adicionar um método não divulgado para atribuir um ID. Isso nem está relacionado ao Entity Framework.
Gert Arnold
1
@GertArnold .. eu tive a mesma pergunta que o OP, encontrei as respostas e transformei-as em uma declaração de linha única, e nunca ouvi falar do termo método não divulgado, cuidado para explicar?
IteratioN7T
3
Isso significa apenas que você não mostra (divulga) tudo o que faz. Talvez não esteja claramente descrito, não sei. O que sei é que Add(se for esse o caso DbSet.Add) não atribui um valor magicamente EmployeeId.
Gert Arnold
3
Não sem SaveChanges. Impossível. A menos que você tenha algum outro processo que atribua EmployeeId, por exemplo, no Employeeconstrutor. OU você está no núcleo da EF usando ForSqlServerUseSequenceHiLo. Enfim, você não está dando a imagem toda.
Gert Arnold
3
Minha última observação será: esse não é o comportamento padrão da EF. Você deve fornecer mais detalhes do seu ambiente. Versão EF, marca e versão do banco de dados, classe Employee, seus detalhes de mapeamento.
Gert Arnold
3
Repository.addorupdate(entity, entity.id);
Repository.savechanges();
Var id = entity.id;

Isso vai funcionar.

Saket Choubey
fonte
4
O repositório não é responsável por salvar as alterações no banco de dados. É o trabalho de um UnitOfWork.
tchelidze
5
Além disso, não está absolutamente claro o que Repositoryé. E "isso vai funcionar" é uma explicação!
Gert Arnold
2

Existem duas estratégias:

  1. Use o banco de dados gerado ID( intouGUID )

    Contras:

    Você deve executar SaveChanges()para obter oID apenas as entidades salvas.

    Prós:

    Pode usar intidentidade.

  2. Usar cliente gerado ID - apenas GUID.

    Prós: Minificação de SaveChanges operações. Capaz de inserir um grande gráfico de novos objetos por uma operação.

    Contras:

    Permitido apenas para GUID

Vladislav Furdak
fonte
1

Quando você usa o código EF 6.x primeiro

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

e inicializar uma tabela de banco de dados, ele colocará um

(newsequentialid())

dentro das propriedades da tabela, sob o cabeçalho Valor padrão ou Ligação, permitindo que o ID seja preenchido à medida que é inserido.

O problema é se você criar uma tabela e adicionar o

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]

parte depois, futuros bancos de dados de atualização não adicionarão novamente o (newsequentialid ())

Corrigir a maneira correta é limpar a migração, excluir o banco de dados e migrar novamente ... ou você pode simplesmente adicionar (newsequentialid ()) ao designer da tabela.

Jeff Li
fonte
Você pode elaborar para onde vai newsequentialid ()? Já tenho modelos de banco de dados criados à mão, sem usar o código EF primeiro, e ele não preenche o ID porque não é minha chave primária. Adoraria encontrar uma solução para isso.
Josh
1
@josh Supondo que o código primeiro seja do tipo Guid, clique com o botão direito do mouse na tabela no Sql Server Management Studio, clique na coluna Id e, na guia Propriedades da coluna, dentro de (Geral), você verá Valor padrão ou Vinculação. Se você estiver criando tabelas de banco de dados manualmente, consulte NewSequentialId ou NewId . O caso de uso geral é algo comowhen -column- is NULL, then NEWID()
Jeff Li