Estrutura da entidade: “A declaração de atualização, inserção ou exclusão de armazenamento afetou um número inesperado de linhas (0).” [fechadas]

324

Estou usando o Entity Framework para preencher um controle de grade. Às vezes, quando faço atualizações, recebo o seguinte erro:

A instrução de atualização, inserção ou exclusão de armazenamento afetou um número inesperado de linhas (0). As entidades podem ter sido modificadas ou excluídas desde que as entidades foram carregadas. Atualize as entradas do ObjectStateManager.

Não consigo descobrir como reproduzir isso. Mas pode ter algo a ver com o quão próximos eu faço as atualizações. Alguém viu isso ou alguém sabe a que a mensagem de erro se refere?

Edit: Infelizmente, não tenho mais liberdade para reproduzir o problema que estava tendo aqui, porque me afastei deste projeto e não me lembro se encontrei uma solução, se outro desenvolvedor a corrigiu ou se eu trabalhei em torno dela. Portanto, não posso aceitar nenhuma resposta.

opiniões fortes
fonte
Eu recebi esse erro com a introdução de uma diretiva de segurança em nível de linha do SQL Server que permitia atualizações em uma linha em um estado que não podia ser lido novamente (um predicado FILTER exclusivo com um predicado BLOCK permissivo) . O EntityFramework exige que a linha atualizada seja lida novamente após a atualização, caso contrário, assume que foi um erro de simultaneidade (pelo menos ao usar a simultaneidade otimista).
Xr280xr
O problema pode ter um escopo incorreto para o seu DBContext stackoverflow.com/questions/49154250/… (este exemplo é para identidade do ASPNET, mas aplica-se a qualquer contexto) #
1155 Simon_Weaver
Independentemente do contexto desse erro, é uma boa ideia colocar um ponto de interrupção onde quer que o contexto esteja sendo instanciado. Você esperava que ela fosse instanciada uma vez quando você carregou uma página da Web, mas está atingindo esse ponto de interrupção 5 vezes? Então você provavelmente tem uma condição de corrida. Veja Request.Uripara ver o URL de solicitação real. No meu caso, eu tinha uma lógica de rastreamento que estava atingindo meu site e carregando desnecessariamente o contexto do banco de dados (e ocasionalmente atualizando-o também). Então a página em que eu estava depurando teve seus dados gravados por uma lógica estúpida de código de rastreamento.
Simon_Weaver
adicionar @ Html.AntiForgeryToken () na vista
Vikas Sharma

Respostas:

199

Esse é um efeito colateral de um recurso chamado simultaneidade otimista.

Não tenho 100% de certeza de como ativá-lo / desativá-lo no Entity Framework, mas basicamente o que está dizendo é que, quando você retirou os dados do banco de dados e quando salvou as alterações, alguém alterou os dados (o que significava quando você foi para salvá-lo, 0 linhas foram atualizadas). Em termos de SQL, updatea wherecláusula de sua consulta contém o valor original de todos os campos da linha e, se 0 linhas forem afetadas, ele saberá que algo deu errado.

A idéia por trás disso é que você não substituirá uma alteração que seu aplicativo não sabia que aconteceu - é basicamente uma pequena medida de segurança lançada pelo .NET em todas as suas atualizações.

Se for consistente, é provável que esteja acontecendo dentro de sua própria lógica (por exemplo, você está atualizando os dados por outro método entre o select e a atualização), mas pode ser simplesmente uma condição de corrida entre dois aplicativos.

fyjham
fonte
34
Isso está acontecendo em um ambiente de usuário único (na minha máquina de desenvolvimento), então não acho que possa ser uma condição de corrida. Estou vinculando a um controle de grade personalizado com um EntityDataSource, por isso não tenho certeza do que está acontecendo nos bastidores, mas não tenho nenhum código extra que modifique as tabelas. Existe uma maneira de alterar essa configuração de simultaneidade?
Strongopinions 4/12/2009
3
Eu acho que você pode, por coluna, no seu modelo de entidade (está na janela de propriedades), mas o problema é que isso impedirá que você veja o erro e ainda não atualizará nada. Você é capaz de visualizar os comandos SQL que estão no seu banco de dados (EG: SQL Server Profiler for MSSQL)? Dessa forma, você pode ver qual atualização é gerada e deve saber por que essa atualização não afeta nenhuma linha.
fyjham 4/12/2009
9
Se a entidade tiver uma propriedade de carimbo de data / hora, certifique-se de armazená-la em sua exibição e verifique se a entidade preenche o carimbo de data e hora corretamente.
anIBMer
Eu tinha uma coluna timestamp e uma vez me dirigi a ele, EF6.1 funcionou como esperado, obrigado pela @anelBMer ponta
JQII
3
Se você usa registros de data e hora, o objeto que você deseja excluir precisa do conjunto PK e da Propriedade RowVersion para atualizá-lo com sucesso! Eu estava definindo a propriedade rowVersion (timestamp), depois de anexar o objeto ao respectivo DbSet, por isso não funcionou. Bom trabalho!
Legends
394

Eu me deparei com isso e foi causado pelo campo de ID (chave) da entidade não estar definido. Portanto, quando o contexto foi salvar os dados, não foi possível encontrar um ID = 0. Certifique-se de colocar um ponto de interrupção na sua declaração de atualização e verifique se o ID da entidade foi definido.

Do comentário de Paul Bellora

Eu tive esse problema exato, causado pelo esquecimento de incluir a entrada de ID oculta na página de edição .cshtml

webtrifusion
fonte
3
+1 Eu estava tendo o mesmo problema e isso ajudou a encontrar a solução. Acontece que eu tinha [Bind (Exclude = "OrderID")] no meu modelo de pedido, o que estava causando o valor do ID da entidade ser zero no HttpPost.
Escape
2
Era exatamente isso que eu estava perdendo. ID do meu objeto era 0.
Azhar Khorasany
4
@ Html.HiddenFor (model => model.productID) - funcionou perfeitamente. Eu estava faltando o productID na página de edição (MVC RAZOR)
Ravi Ram
2
Eu tive um problema semelhante, mas com um toque. Para mim, o problema era que eu não tinha a tabela sql configurada corretamente. Meu campo de chave primária não foi definido para incremento automático. Então EF iria enviar o disco que eu estava tentando inserir w / oa chave que é bom se você se lembrar de dizer sql que o campo é um campo de identidade auto incremento, que eu esqueci: <
Agile Noob
1
Mesmo problema, mas usando uma chave composta. Um dos valores-chave não foi definido.
Obaylis
113

Uau, muitas respostas, mas recebi esse erro quando fiz algo ligeiramente diferente que ninguém mais mencionou.

Para encurtar a história, se você criar um novo objeto e informar à EF que ela foi modificada usando o EntityState.Modifiedcomando, ele emitirá esse erro, pois ainda não existe no banco de dados. Aqui está o meu código:

MyObject foo = new MyObject()
{
    someAttribute = someValue
};

context.Entry(foo).State = EntityState.Modified;
context.SaveChanges();

Sim, isso parece idiota, mas surgiu porque o método em questão costumava ter foopassado para ele tendo sido criado anteriormente, agora só someValuepassou para ele e se cria foo.

Reparo fácil, basta mudar EntityState.Modifiedpara EntityState.Addedou alterar essa linha inteira para:

context.MyObject.Add(foo);
Ben
fonte
Obrigado por postar isso. Esse também era meu problema, eu tinha copiado e colado algum código que estava definindo o Estado como EntityState.Modified.
clayRay
23

Eu estava enfrentando esse mesmo erro assustador ... :) Então eu percebi que estava esquecendo de definir um

@Html.HiddenFor(model => model.UserProfile.UserId)

para a chave primária do objeto que está sendo atualizado! Costumo esquecer essa coisa simples, mas muito importante!

A propósito: HiddenForé para o ASP.NET MVC.

Leniel Maccaferri
fonte
3
Isso parece uma falha de segurança, para armazenar o UserIdna forma, muito propenso a hackers ... isso deve ser preenchida depois deHttpContext.Current.User.Identity.Name
Serj Sagan
@SerjSagan, você está certo ... mas contanto que você faça algumas verificações no servidor para confirmar o UserId e o UserName atual, você estará pronto.
22313 Leniel Maccaferri
1
O HiddenForque quero dizer é que, mesmo armazenando isso, você precisará obtê-lo de HttpContextqualquer maneira ... Eu não colocaria essa propriedade no formulário, o que me forçaria a sempre preenchê-la no lado do servidor ...
Serj Sagan
16

Verifique se você esqueceu o atributo "DataKeyNames" no GridView. é uma obrigação ao modificar dados no GridView

http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.datakeynames.aspx

Solly
fonte
+1. Solução perfeita e simples para mim. Estou vinculando GridView a EntityDataSource e não defini isso para minha chave primária no objeto.
Andez
Sabemos que a interface do usuário do Kendo não suporta chave composta, mas, caso eu tenha adicionado uma nova coluna que concatenasse minhas chaves a uma, o que está acontecendo?
Branislav
15

O problema é causado por uma de duas coisas: -

  1. Você tentou atualizar uma linha com uma ou mais propriedades are Concurrency Mode: Fixed.. e a simultaneidade otimista impediu que os dados fossem salvos. Ou seja. alguns alteraram os dados da linha entre o momento em que você recebeu os dados do servidor e quando os salvou.
  2. Você tentou atualizar ou excluir uma linha, mas a linha não existe. Outro exemplo de alguém alterando os dados (neste caso, removendo) entre uma recuperação e depois salve OU você está tentando atualizar um campo que não é uma Identidade (ou seja, StoreGeneratedPattern = Computed) e essa linha não existe.
Pure.Krome
fonte
1
Isso também pode ser causado se todas as propriedades do objeto às quais foram atribuídas forem atribuídas com os mesmos valores que tinham antes.
Serj Sagan
+1 para o segundo. Eu tinha StoreGeneratedPattern = None, mudando para StoreGeneratedPattern = Identity resolveu o problema. Obrigado
tkt986
12

Eu recebi esse mesmo erro porque parte da PK era uma coluna de data e hora e o registro sendo inserido usava DateTime.Now como o valor dessa coluna. A estrutura da entidade inseria o valor com precisão de milissegundos e, em seguida, procurava o valor que acabou de inserir também com precisão de milissegundos. No entanto, o SqlServer arredondou o valor para a segunda precisão e, portanto, a estrutura da entidade não conseguiu encontrar o valor de precisão em milissegundos.

A solução foi truncar os milissegundos de DateTime.Now antes de inserir.

innominate227
fonte
2
Tivemos o mesmo problema, exceto que foram inserindo em uma Datecoluna com um DateTimevalor
adam0101
1
O mesmo aqui. Tínhamos um registro de data warehouse e estávamos usando o registro de data e hora como parte da chave. O registro de data e hora no data warehouse era um SQL DateTime, mas o registro de data e hora em C # não era correspondente. Alterei o tipo de dados SQL para DateTime2 (7), atualizei o modelo EF e tudo foi corrigido.
mmcfly
Alterar a coluna para Datetime2 (7) também funcionou para mim. Obrigado @mmcfly
Dzejms
10

Eu estava com o mesmo problema e a resposta da @ webtrifusion ajudou a encontrar a solução.

Meu modelo estava usando o Bind(Exclude)atributo no ID da entidade que estava causando o valor do ID da entidade ser zero no HttpPost.

namespace OrderUp.Models
{
[Bind(Exclude = "OrderID")]
public class Order
{
    [ScaffoldColumn(false)]
    public int OrderID { get; set; }

    [ScaffoldColumn(false)]
    public System.DateTime OrderDate { get; set; }

    [Required(ErrorMessage = "Name is required")]
    public string Username { get; set; }
    }
}   
Exaustão
fonte
Problema semelhante, por razões de segurança, tenho o Bind (include = alguns campos). O ID não estava na lista. Também o adicionei como uma entrada oculta. Deve ter apagado algo gerado pelo MVC ou o ID não estava lá. Obrigado pela ajuda.
MusicAndCode
10

Eu tive o mesmo problema, acho que foi causado pelo RowVersion que era nulo. Verifique se seu ID e sua RowVersion não são nulos .

para mais informações, consulte este tutorial

http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/handling-concurrency-with-the-entity-framework-in-an-asp-net-mvc-application

Bilel Chaouadi
fonte
versão de linha foi nula no meu caso
Prakash
No meu caso, eu removi acidentalmente o campo Id no meu [Bind (Include = properties)]. Adicione de volta e funcionou bem.
Caverman 12/05
8

Comecei a receber esse erro depois de mudar do modelo primeiro para o primeiro código. Eu tenho vários threads atualizando um banco de dados onde alguns podem atualizar a mesma linha. Não sei por que não tive um problema ao usar o modelo primeiro, suponha que ele use um padrão de simultaneidade diferente.

Para lidar com isso em um local sabendo as condições sob as quais isso pode ocorrer, adicionei a seguinte sobrecarga à minha classe DbContext:

using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;

public class MyDbContext: DbContext {
...
        public int SaveChanges(bool refreshOnConcurrencyException, RefreshMode refreshMode = RefreshMode.ClientWins) {
            try {
                return SaveChanges();
            }
            catch (DbUpdateConcurrencyException ex) {
                foreach (DbEntityEntry entry in ex.Entries) {
                    if (refreshMode == RefreshMode.ClientWins)
                        entry.OriginalValues.SetValues(entry.GetDatabaseValues());
                    else
                        entry.Reload();
                }
                return SaveChanges();
            }
        }
}

Em seguida, chamado SaveChanges(true)sempre que aplicável.

avenmore
fonte
1
OK, todo mundo está reclamando sobre o problema, mostrando como eles podem desencadear etc., mas essa resposta tem uma resposta legal. Eu uso um modelo de atualização contínua (sem botão salvar aqui, baby) e estava recebendo isso nas atualizações de grade quando o segmento EF estava ficando para trás e o resolvi. Trabalho brilhante, meu bom nome ... você me fez parecer um herói - parado no ombro de gigantes !!
Tony Trembath-Drake
Me ajudou muito, olhe para isto, para mais opções- stackoverflow.com/a/13891724/4836581
Zvi Redler
7

Você precisa incluir explicitamente um BoundField da chave primária. Se você não deseja que o usuário veja a chave primária, é necessário ocultá-la via css:

    <asp:BoundField DataField="Id_primary_key" ItemStyle-CssClass="hidden" 
HeaderStyle-CssClass="hidden" />

Onde 'hidden' é uma classe em css cuja exibição é definida como 'none'.

Paulo
fonte
1
hah, você me informou que eu excluí meu campo de identificação oculta no asp.net MVC. Obrigado @Paulo! :)
Tomasz Iniewicz
7

Durante a edição, inclua o ID ou a chave primária da entidade como um campo oculto na exibição

ie

      @Html.HiddenFor(m => m.Id)

isso resolve o problema.

Além disso, se o seu modelo incluir itens não utilizados, inclua-o também e publique-o no controlador

Arun Aravind
fonte
7

Eu também me deparei com esse erro. O problema foi causado por um gatilho na mesa que eu estava tentando salvar. O gatilho usou 'INSTEAD OF INSERT', o que significa que 0 linhas já foram inseridas nessa tabela, daí o erro. Felizmente, no caso de a funcionalidade do gatilho estar incorreta, mas acho que poderia ser uma operação válida que, de alguma forma, deveria ser manipulada no código. Espero que isso ajude alguém um dia.

Pecado
fonte
2
A entidade pode ser levada a crer que as linhas foram adicionadas retornando uma instrução SELECT (com a coluna da chave primária) do acionador.
jahu
1
Para expandir o comentário de @jahu, tive que obter um ID real do item recém-inserido a ser retornado do meu gatilho e o nome da coluna deve corresponder à coluna de identidade da tabela de gatilhos (no meu caso, na verdade, uma exibição para que não tinha uma identidade própria, mas eu tinha enganado o edmx a acreditar que ele tinha). Meu gatilho estava fazendo uma inserção em uma tabela separada, então eu só adicionado este última linha para meu gatilho:SELECT SCOPE_IDENTITY() as MyViewId
DannyMeister
Consulte também esta pergunta: stackoverflow.com/questions/5820992/…
J. Polfer
No meu caso, eu estava fazendo uma operação de exclusão em entidades em uma coleção filho, mas houve um gatilho na exclusão de uma das entidades filho que causou a exclusão de outra entidade filho. Isso causou o erro, pois as linhas N-1 foram afetadas devido ao acionamento da exclusão de uma das entidades filhas antes da estrutura da entidade tentar excluí-la.
Skeletank #
6

Me deparei com esse problema em uma tabela em que faltava uma chave primária e tinha uma coluna DATETIME (2, 3) (portanto, a "chave primária" da entidade era uma combinação de todas as colunas) ... Ao executar a inserção, o carimbo de data e hora tinha um horário mais preciso (2018-03-20 08: 29: 51.8319154) que foi truncado para (2018-03-20 08: 29: 51.832) para que a pesquisa nos campos-chave falhe.

combatc2
fonte
5

Eu também tive esse erro. Existem algumas situações em que a Entidade pode não estar ciente do Contexto de Banco de Dados real que você está usando ou o Modelo pode ser diferente. Para isso, defina: EntityState.Modified; para EntityState.Added;

Para fazer isso:

if (ModelState.IsValid)
{
context.Entry(yourModelReference).State = EntityState.Added;
context.SaveChanges();
}

Isso garantirá que a Entidade saiba que você está usando ou adicionando o Estado com o qual está trabalhando. Nesse ponto, todos os valores de modelo corretos precisam ser definidos. Cuidado para não perder nenhuma alteração que possa ter sido feita em segundo plano.

Espero que isto ajude.

Prego enferrujado
fonte
1
você é um gurú! funciona para mim!
Hernaldo Gonzalez
5
  @Html.HiddenFor(model => model.RowVersion)

Minha versão de linha era nula, então tive que adicionar isso à exibição que resolveu meu problema

Prakash
fonte
Não estava passando o RowVersion do modo de exibição para a ação de edição, além disso, esqueci de vincular o modelo ao RowVersion. No momento em que você está salvando o objeto no banco de dados, é necessário o valor anterior do envio de RowVersion para o banco de dados junto com o objeto para a verificação de simultaneidade. Você comete erros tolos quando precisa de coisas mais rapidamente!
precisa saber é o seguinte
5

A linha [DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.None)]fez o truque no meu caso:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;


[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int? SomeNumber { get; set; }
Tomo
fonte
4

Apenas certifique-se de que a tabela e o formulário tenham a chave primária e o edmx atualizados.

Descobri que os erros durante a atualização geralmente eram devidos a: - Nenhuma chave primária na tabela - Nenhuma chave primária na visualização / formulário Editar (por exemplo @Html.HiddenFor(m=>m.Id)

Moji
fonte
4

Eu tive o mesmo problema. No meu caso, eu estava tentando atualizar a chave primária, o que não é permitido.

ajaysinghdav10d
fonte
4

Eu recebi esse erro esporadicamente ao usar um asyncmétodo. Não aconteceu desde que mudei para um método síncrono.

Erros esporadicamente:

[Authorize(Roles = "Admin")]
[HttpDelete]
[Route("file/{id}/{customerId}/")]
public async Task<IHttpActionResult> Delete(int id, int customerId)
{
    var file = new Models.File() { Id = id, CustomerId = customerId };
    db.Files.Attach(file);
    db.Files.Remove(file);

    await db.SaveChangesAsync();

    return Ok();
}

Funciona o tempo todo:

[Authorize(Roles = "Admin")]
[HttpDelete]
[Route("file/{id}/{customerId}/")]
public IHttpActionResult Delete(int id, int customerId)
{
    var file = new Models.File() { Id = id, CustomerId = customerId };
    db.Files.Attach(file);
    db.Files.Remove(file);

    db.SaveChanges();

    return Ok();
}
Ogglas
fonte
Embora isso tenha resolvido meu problema, ele serviu para apontar para o problema subjacente mencionado anteriormente neste post sobre versões de PKs e linhas. Eu tinha deixado de adicionar um mapa de esquema para uma nova tabela que era ainda mais complicada pelo fato de o PK não seguir a regra da convenção de nomenclatura. ID <Nome da tabela>.
Midohioboarder
3

Eu recebi esse erro quando estava excluindo algumas linhas no banco de dados (no loop) e adicionando as novas na mesma tabela.

As soluções para mim foram: criar dinamicamente um novo contexto em cada iteração de loop

Tony
fonte
Eu tive que fazer a mesma coisa, ainda não sei por que o problema ocorreu, mas isso funciona.
precisa saber é o seguinte
3
    public void Save(object entity)
    {
        using (var transaction = Connection.BeginTransaction())
        {
        try
                {
                    SaveChanges();
                    transaction.Commit();
                }
                catch (OptimisticConcurrencyException)
                {
                    if (ObjectStateManager.GetObjectStateEntry(entity).State == EntityState.Deleted || ObjectStateManager.GetObjectStateEntry(entity).State == EntityState.Modified)
                        this.Refresh(RefreshMode.StoreWins, entity);
                    else if (ObjectStateManager.GetObjectStateEntry(entity).State == EntityState.Added)
                        Detach(entity);
                    AcceptAllChanges(); 
                    transaction.Commit();
                }
        }
    }
Prem Prakash
fonte
Você pode esclarecer a que 'isso' está se referindo aqui e o que é ObjectStateManager? Eu estou tentando isso em nossa classe repositório de base, mas recebendo erros
Naomi
3

Isso também acontecerá se você estiver tentando inserir em uma situação de restrição única, ou seja, se você puder ter apenas um tipo de endereço por empregador e tentar inserir um segundo desse mesmo tipo com o mesmo empregador, obterá o mesmo problema .

OU

Isso também poderia acontecer se todas as propriedades do objeto às quais foram atribuídas fossem atribuídas com os mesmos valores que tinham antes.

        using(var db = new MyContext())
        {
            var address = db.Addresses.FirstOrDefault(x => x.Id == Id);

            address.StreetAddress = StreetAddress; // if you are assigning   
            address.City = City;                   // all of the same values
            address.State = State;                 // as they are
            address.ZipCode = ZipCode;             // in the database    

            db.SaveChanges();           // Then this will throw that exception
        }
Serj Sagan
fonte
2

Se você estiver tentando criar mapeamento no seu arquivo edmx para uma "função Importação", isso pode resultar neste erro. Apenas limpe os campos para inserir, atualizar e excluir localizados em Detalhes do mapeamento para uma determinada entidade em seu edmx, e deve funcionar. Espero ter deixado claro.

Mubarak
fonte
2

Eu recebi essa exceção ao anexar um objeto que não existia no banco de dados. Eu assumi que o objeto foi carregado de um contexto separado, mas se foi a primeira vez que o usuário visitou o site, o objeto foi criado do zero. Temos chaves primárias de incremento automático, para que eu possa substituir

context.Users.Attach(orderer);

com

if (orderer.Id > 0) {
    context.Users.Attach(orderer);
}
Andrew
fonte
2

Bem, eu tenho esse mesmo problema. Mas isso foi devido ao meu próprio erro. Na verdade, eu estava salvando um objeto em vez de adicioná-lo. Então esse foi o conflito.

Todos
fonte
2

Uma maneira de depurar esse problema em um ambiente do Sql Server é usar o Sql Profiler incluído na sua cópia do SqlServer ou, se usar a versão Express, obtenha uma cópia do Express Profiler gratuitamente no CodePlex, seguindo o link abaixo:

Express Profiler

Usando o Sql Profiler, você pode acessar o que estiver sendo enviado pela EF ao banco de dados. No meu caso, isso equivale a:

exec sp_executesql N'UPDATE [dbo].[Category]
SET [ParentID] = @0, [1048] = NULL, [1033] = @1, [MemberID] = @2, [AddedOn] = @3
WHERE ([CategoryID] = @4)
',N'@0 uniqueidentifier,@1 nvarchar(50),@2 uniqueidentifier,@3 datetime2(7),@4 uniqueidentifier',
@0='E060F2CA-433A-46A7-86BD-80CD165F5023',@1=N'I-Like-Noodles-Do-You',@2='EEDF2C83-2123-4B1C-BF8D-BE2D2FA26D09',
@3='2014-01-29 15:30:27.0435565',@4='3410FD1E-1C76-4D71-B08E-73849838F778'
go

Copiei colei isso em uma janela de consulta no Sql Server e o executei. Com certeza, embora tenha sido executado, 0 registros foram afetados por esta consulta, portanto, o erro está sendo retornado pelo EF.

No meu caso, o problema foi causado pelo CategoryID.

Não houve um ID da categoria identificado pelo ID EF enviado ao banco de dados, portanto, 0 registro foi afetado.

Porém, isso não foi culpa da EF, mas sim um coalescente nulo de buggy "??" em um View Controller que estava enviando bobagens para a camada de dados.

arriscar
fonte
2

Nenhuma das respostas acima cobriu completamente minha situação e a solução para ela.

Código em que o erro foi gerado no controlador MVC5:

        if (ModelState.IsValid)
        {
            db.Entry(object).State = EntityState.Modified; 
            db.SaveChanges(); // line that threw exception
            return RedirectToAction("Index");
        }

Eu recebi essa exceção quando estava salvando um objeto em uma exibição Editar. O motivo pelo qual foi lançado foi porque, quando voltei para salvá-lo, havia modificado as propriedades que formavam a chave primária no objeto. Portanto, definir seu estado como Modificado não fazia sentido para a EF - era uma nova entrada, não uma salva anteriormente.

Você pode resolver isso usando A) modificando a chamada de salvar para Adicionar o objeto ou B) apenas não alterando a chave primária na edição. Eu fiz B).

J. Polfer
fonte
2

Quando a resposta aceita disse " ela não substituirá uma alteração que seu aplicativo não sabia que aconteceu ", fiquei cético porque meu objeto foi criado recentemente. Mas acontece que havia um INSTEAD OF UPDATE, INSERT- TRIGGERanexo à tabela que estava atualizando uma coluna calculada da mesma tabela.

Depois que mudei para AFTER INSERT, UPDATE, estava funcionando bem.

Mahesh
fonte
2

Isso aconteceu comigo devido a uma incompatibilidade entre datetime e datetime2. Estranhamente, funcionou bem antes de um testador descobrir o problema. O modelo My Code First incluiu um DateTime como parte da chave primária:

[Key, Column(Order = 2)]  
public DateTime PurchasedDate { get; set; } = (DateTime)SqlDateTime.MinValue;

A coluna gerada é uma coluna de data e hora. Ao chamar SaveChanges, o EF gerou o seguinte SQL:

-- Region Parameters
DECLARE @0 Int = 2
DECLARE @1 Int = 25
DECLARE @2 Int = 141051
DECLARE @3 DateTime2 = '2017-07-27 15:16:09.2630000' --(will not equal a datetime value)
-- EndRegion
UPDATE [dbo].[OrganizationSurvey]
SET [OrganizationSurveyStatusId] = @0
WHERE ((([SurveyID] = @1) AND ([OrganizationID] = @2)) AND ([PurchasedDate] = @3))

Como estava tentando corresponder uma coluna datetime com um valor datetime2, ele não retornou resultados. A única solução em que consegui pensar foi alterar a coluna para um datetime2:

[Key, Column(Order = 2, TypeName = "DateTime2")]  
public DateTime PurchasedDate { get; set; } = (DateTime)SqlDateTime.MinValue;
R. Salisbury
fonte
1
A estranheza dele vs. trabalho não trabalhar tem a ver com o subjacente formato / base de datetimevs. datetime2. Essencialmente, alguns valores de milissegundos serão avaliados para uma correspondência, outros não. O mesmo aconteceu comigo e eu também mudei para DateTime2.
xr280xr
+1 Eu gostaria de poder +100 neste aqui para você. Depois de ler em muitos lugares, finalmente encontrei isso e percebi que, na verdade, eu tinha um Datetime como parte da minha chave primária. Sim, isso realmente consertou. Atualizei a coluna para Datetime2 e funcionou. Agora, minha discussão é com o Entity Framework para elaborar uma consulta tão ruim para isso que me obriga a fazer isso.
Catchops