Ao executar SubmitChanges para o DataContext após atualizar algumas propriedades com uma conexão LINQ to SQL (em relação ao SQL Server Compact Edition), obtenho uma "Linha não encontrada ou alterada." ChangeConflictException.
var ctx = new Data.MobileServerDataDataContext(Common.DatabasePath);
var deviceSessionRecord = ctx.Sessions.First(sess => sess.SessionRecId == args.DeviceSessionId);
deviceSessionRecord.IsActive = false;
deviceSessionRecord.Disconnected = DateTime.Now;
ctx.SubmitChanges();
A consulta gera o seguinte SQL:
UPDATE [Sessions]
SET [Is_Active] = @p0, [Disconnected] = @p1
WHERE 0 = 1
-- @p0: Input Boolean (Size = 0; Prec = 0; Scale = 0) [False]
-- @p1: Input DateTime (Size = 0; Prec = 0; Scale = 0) [9/4/2008 5:12:02 PM]
-- Context: SqlProvider(SqlCE) Model: AttributedMetaModel Build: 3.5.21022.8
O problema óbvio é WHERE 0 = 1. Depois que o registro foi carregado, confirmei que todas as propriedades em "deviceSessionRecord" estão corretas para incluir a chave primária. Além disso, ao capturar a "ChangeConflictException", não há informações adicionais sobre o motivo da falha. Também confirmei que essa exceção é lançada com exatamente um registro no banco de dados (o registro que estou tentando atualizar)
O que é estranho é que eu tenho uma instrução de atualização muito semelhante em uma seção diferente do código e ela gera o seguinte SQL e de fato atualiza meu banco de dados SQL Server Compact Edition.
UPDATE [Sessions]
SET [Is_Active] = @p4, [Disconnected] = @p5
WHERE ([Session_RecId] = @p0) AND ([App_RecId] = @p1) AND ([Is_Active] = 1) AND ([Established] = @p2) AND ([Disconnected] IS NULL) AND ([Member_Id] IS NULL) AND ([Company_Id] IS NULL) AND ([Site] IS NULL) AND (NOT ([Is_Device] = 1)) AND ([Machine_Name] = @p3)
-- @p0: Input Guid (Size = 0; Prec = 0; Scale = 0) [0fbbee53-cf4c-4643-9045-e0a284ad131b]
-- @p1: Input Guid (Size = 0; Prec = 0; Scale = 0) [7a174954-dd18-406e-833d-8da650207d3d]
-- @p2: Input DateTime (Size = 0; Prec = 0; Scale = 0) [9/4/2008 5:20:50 PM]
-- @p3: Input String (Size = 0; Prec = 0; Scale = 0) [CWMOBILEDEV]
-- @p4: Input Boolean (Size = 0; Prec = 0; Scale = 0) [False]
-- @p5: Input DateTime (Size = 0; Prec = 0; Scale = 0) [9/4/2008 5:20:52 PM]
-- Context: SqlProvider(SqlCE) Model: AttributedMetaModel Build: 3.5.21022.8
Confirmei que os valores de campos primários adequados foram identificados no esquema de banco de dados e no DBML que gera as classes LINQ.
Eu acho que esta é quase uma questão de duas partes:
- Por que a exceção está sendo lançada?
- Depois de revisar o segundo conjunto de SQL gerado, parece que para detectar conflitos seria bom verificar todos os campos, mas imagino que isso seja bastante ineficiente. É assim que sempre funciona? Existe uma configuração para apenas verificar a chave primária?
Tenho lutado contra isso nas últimas duas horas, então qualquer ajuda seria apreciada.
fonte
Respostas:
Isso é desagradável, mas simples:
Verifique se os tipos de dados para todos os campos no O / R-Designer correspondem aos tipos de dados em sua tabela SQL. Verifique novamente para anulável! Uma coluna deve ser anulável no O / R-Designer e no SQL ou não anulável em ambos.
Por exemplo, uma coluna NVARCHAR "título" é marcada como NULLable em seu banco de dados e contém o valor NULL. Mesmo que a coluna seja marcada como NOT NULLable em seu O / R-Mapping, LINQ irá carregá-la com sucesso e definir a string de coluna como nula.
O mesmo sintoma aparecerá quando os tipos de dados de um campo não corresponderem ao tipo de dados no SQL ou se houver campos ausentes, pois o LINQ não será capaz de garantir que os dados SQL não tenham mudado desde a leitura dos dados.
fonte
VARCHAR(MAX) NOT NULL
paraVARCHAR(MAX) NULL
e esperando que funcionasse. Erro muito simples.NUMERIC(12,8)
coluna mapeada para umaDecimal
propriedade. Tive que precisar o DbType no atributo Coluna[Column(DbType="numeric(12,8)")] public decimal? MyProperty ...
Em primeiro lugar, é útil saber o que está causando o problema. Googling solução deve ajudar, você pode registrar os detalhes (tabela, coluna, valor antigo, novo valor) sobre o conflito para encontrar a melhor solução para resolver o conflito mais tarde:
Crie auxiliares para envolver seus sumbitChanges:
Em seguida, chame o código de alterações de envio:
Finalmente, registre a exceção em seu manipulador de exceção global:
fonte
Existe um método no DataContext chamado Refresh que pode ajudar aqui. Ele permite que você recarregue o registro do banco de dados antes que as alterações sejam enviadas e oferece diferentes modos para determinar quais valores manter. "KeepChanges" parece ser o mais inteligente para os meus propósitos, tem como objetivo mesclar minhas alterações com qualquer alteração não conflitante que tenha acontecido no banco de dados nesse ínterim.
Se bem entendi. :)
fonte
dc.Refresh(RefreshMode.KeepChanges,changedObject);
antes de dc.SubmitChangesIsso também pode ser causado pelo uso de mais de um DbContext.
Então, por exemplo:
Esse código falhará de vez em quando, de maneiras que parecem imprevisíveis, porque o usuário é usado em ambos os contextos, alterado e salvo em um e depois salvo no outro. A representação na memória do usuário que possui "Algo" não corresponde ao que está no banco de dados, então você obtém este bug oculto.
Uma maneira de evitar isso é escrever qualquer código que possa ser chamado como um método de biblioteca de forma que receba um DbContext opcional:
Portanto, agora seu método pega um banco de dados opcional e, se não houver um, vai e cria um. Se houver, apenas reutiliza o que foi transmitido. O método auxiliar facilita a reutilização desse padrão em seu aplicativo.
fonte
Resolvi esse erro arrastando de novo uma mesa do explorador de servidores para o designer e reconstruindo.
fonte
Isso é o que você precisa para substituir este erro no código C #:
fonte
Não sei se você encontrou respostas satisfatórias para sua pergunta, mas postei uma pergunta semelhante e, eventualmente, respondi sozinho. Descobriu-se que a opção de conexão padrão NOCOUNT foi ativada para o banco de dados, o que causou uma ChangeConflictException para cada atualização feita com Linq para Sql. Você pode consultar minha postagem aqui .
fonte
Eu consertei isso adicionando
(UpdateCheck = UpdateCheck.Never)
a todas as[Column]
definições.Não parece uma solução apropriada, no entanto. No meu caso, parece estar relacionado ao fato de que esta tabela tem uma associação a outra tabela da qual uma linha é excluída.
Isso está no Windows Phone 7.5.
fonte
No meu caso, o erro foi gerado quando dois usuários com contextos de dados LINQ-to-SQL diferentes atualizaram a mesma entidade da mesma maneira. Quando o segundo usuário tentou a atualização, a cópia que eles tinham em seu contexto de dados estava desatualizada, embora tenha sido lida após a conclusão da primeira atualização.
Eu descobri a explicação e solução neste artigo de Akshay Phadke: https://www.c-sharpcorner.com/article/overview-of-concurrency-in-linq-to-sql/
Aqui está o código que eu mais elaborei:
Quando olhei para minha janela de saída durante a depuração, pude ver que o valor atual correspondia ao valor do banco de dados. O "Valor Original" sempre foi o culpado. Esse foi o valor lido pelo contexto de dados antes de aplicar a atualização.
Obrigado ao MarceloBarbosa pela inspiração.
fonte
Eu sei que esta pergunta já foi respondida há muito tempo, mas aqui eu passei as últimas horas batendo minha cabeça contra a parede e eu só queria compartilhar minha solução que acabou não sendo relacionada a nenhum dos itens neste tópico:
Cache!
A parte select () do meu objeto de dados estava usando cache. Quando se tratava de atualizar o objeto, um erro de linha não encontrada ou alterada estava aparecendo.
Várias das respostas mencionaram o uso de diferentes DataContext e, em retrospecto, é provavelmente o que estava acontecendo, mas não me levou imediatamente a pensar em cache, então espero que isso ajude alguém!
fonte
Recentemente, encontrei esse erro e descobri que o problema não era com meu contexto de dados, mas com uma instrução de atualização disparada dentro de um gatilho depois que o commit foi chamado no contexto. O gatilho estava tentando atualizar um campo não anulável com um valor nulo e estava causando um erro no contexto com a mensagem mencionada acima.
Estou adicionando esta resposta apenas para ajudar outras pessoas a lidar com esse erro e não encontrar uma solução nas respostas acima.
fonte
Também recebi esse erro por usar dois contextos diferentes. Resolvi esse problema usando um único contexto de dados.
fonte
No meu caso, o problema estava nas opções do usuário em todo o servidor. Segue:
https://msdn.microsoft.com/en-us/library/ms190763.aspx
Ativei a opção NOCOUNT na esperança de obter alguns benefícios de desempenho:
e isso acaba quebrando as verificações do Linq para as linhas afetadas (tanto quanto eu posso descobrir a partir de fontes .NET), levando a ChangeConflictException
Redefinir as opções para excluir os 512 bits corrigiu o problema.
fonte
Depois de usar a resposta de qub1n, descobri que o problema para mim era que eu havia declarado inadvertidamente uma coluna do banco de dados como decimal (18,0). Eu estava atribuindo um valor decimal, mas o banco de dados o estava alterando, retirando a parte decimal. Isso resultou no problema de mudança de linha.
Basta adicionar isso se alguém tiver um problema semelhante.
fonte
basta ir com Linq2DB, muito melhor
fonte