Não foi possível atualizar o EntitySet - porque ele possui um DefiningQuery e nenhum elemento <UpdateFunction> existe

534

Estou usando o Entity Framework 1 com .net 3.5.

Estou fazendo algo simples assim:

var roomDetails = context.Rooms.ToList();

foreach (var room in roomDetails)
{        
   room.LastUpdated = DateTime.Now;
}

Estou recebendo esse erro quando tento fazer:

 context.SaveChanges();

Eu recebo o erro:

Não foi possível atualizar o EntitySet - porque ele possui um DefiningQuery e nenhum elemento <UpdateFunction> existe no elemento <ModificationFunctionMapping> para oferecer suporte à operação atual.

Estou fazendo muitas atualizações no contexto e sem problemas, é apenas quando tento atualizar essa entidade específica.

Toda a minha pesquisa mostra a mesma coisa, que não há chave primária declarada na entidade que estou tentando atualizar. Mas, infelizmente, tenho uma chave primária declarada ...

iKode
fonte
61
Cometi um erro, não havia uma chave primária na mesa, obrigado pelo seu tempo! Desculpe pela inconveniência!
iKode 28/09
1
Apenas me aconteceu - provavelmente criado 1000 tabelas com chaves primárias, e esqueceu um - a mensagem de exceção não ajuda muito
Peter Munnings
1
excelente. realmente eu esqueci de adicionar chave primária à tabela. Vamos tentar ser cuidadosa)
AEMLoviji

Respostas:

1024

Isso geralmente acontece porque um dos seguintes motivos:

  • Conjunto de entidades é mapeado na exibição Banco de Dados
  • Uma consulta de banco de dados personalizada
  • A tabela do banco de dados não possui uma chave primária

Depois de fazer isso, você ainda precisará atualizar no designer do Entity Framework (ou excluir a entidade e adicioná-la) antes de parar de receber o erro.

Ladislav Mrnka
fonte
2
Altere também store: Schema para apenas Schema para esse EntitySet, se você ainda estiver tendo problemas.
Geoff
53
Em seguida, exclua e recrie a entidade porque a atualização não funciona corretamente no designer EF.
Suncat2000
48
PK foi a resposta. Obrigado!
Nrod 03/04
1
A atualização no designer EF funcionou bem para mim depois de adicionar a chave primária ao banco de dados. Usando EF 5.0 e .net 4.0
StillLearnin
1
O mesmo aqui ! Thx ... teve que remover a tabela e adicionar novamente à EF para que ela
demorasse
90

Basta adicionar uma chave primária à tabela. É isso aí. Problema resolvido.

ALTER TABLE <TABLE_NAME>
ADD CONSTRAINT <CONSTRAINT_NAME> PRIMARY KEY(<COLUMN_NAME>)
Jebastin J
fonte
13
e não se esqueça de clicar em "Modelo de atualização do banco de dados" no seu arquivo edmx
Bashar Abu Shamaa
@BasharAbuShamaa esta resposta não é válida sem esse detalhe.
Kehlan Krumme
66

Este é o meu caso. A simples remoção resultou em outro erro. Eu segui os passos deste post, exceto o último. Para sua conveniência, copiei as 4 etapas da postagem que segui para resolver o problema da seguinte maneira:

  1. Clique com o botão direito do mouse no arquivo edmx, selecione Abrir com, editor XML
  2. Localize a entidade no elemento edmx: StorageModels
  3. Remova completamente o DefiningQuery
  4. Renomeie o store:Schema="dbo"para Schema="dbo"(caso contrário, o código gerará um erro dizendo que o nome é inválido)
kavitha Reddy
fonte
Muito obrigado - foi exatamente isso que resolveu o meu problema. É bastante perturbador que isso não tenha sido corrigido na EF. E, incrível que você tenha descoberto isso!
Bicycle Dave
Tentei excluir a entidade e adicioná-la novamente. Recompilando. Limpeza. Nada funcionou para mim, exceto isso.
Vintastic
1
Isso resolveu meu problema ainda não sei como você encontrou as respostas e por que sua sugestão resolveu o problema.
swcraft
O que acontece se você precisar atualizar o modelo de banco de dados? Eu fiz um "Update Model from Database" e ele deixou meu modelo totalmente inutilizável. Eu tive que desfazer e começar de novo. Se existe uma maneira de contornar isso?
Gary
Essa é uma questão realmente estranha. Existe alguma informação sobre como esse problema ocorre para evitá-lo? No entanto - ajudou
r3dst0rm
41

Observe que talvez sua Entidade tenha chave primária, mas sua tabela no banco de dados não possua chave primária .

Majid
fonte
1
Como superar, se não podemos alterar a tabela do banco de dados?
Kai Hartmann #
Se você puder alterar a tabela do banco de dados para ter uma chave primária, o gerador de código deixará de cometer os mesmos erros, remover a chave do EF causará muitos outros problemas.
Chris Schaller
30

ATUALIZAÇÃO: recebi alguns votos positivos sobre isso ultimamente, então achei que deixaria as pessoas saberem que os conselhos que dou abaixo não são os melhores. Desde que comecei a mexer no Entity Framework em bancos de dados sem chave antigos, percebi que a melhor coisa que você pode fazer BY FAR é fazê-lo revertendo o código primeiro. Existem alguns bons artigos por aí sobre como fazer isso. Basta segui-los e, quando desejar adicionar uma chave, use anotações de dados para "falsificar" a chave.

Por exemplo, digamos que eu saiba que minha mesa Orders, embora não tenha uma chave primária, garante apenas um número de pedido por cliente. Como essas são as duas primeiras colunas da tabela, eu configuraria o código das primeiras classes para ficar assim:

    [Key, Column(Order = 0)]
    public Int32? OrderNumber { get; set; }

    [Key, Column(Order = 1)]
    public String Customer { get; set; }

Ao fazer isso, você basicamente finge que a EF acredita que há uma chave de cluster composta por OrderNumber e Customer. Isso permitirá que você faça inserções, atualizações, etc. na sua mesa sem chave.

Se você não está muito familiarizado com a reversão do Code First, encontre um bom tutorial sobre o Entity Framework Code First. Em seguida, encontre um no Reverse Code First (que está executando o Code First com um banco de dados existente). Depois, volte aqui e olhe para os meus principais conselhos novamente. :)

Resposta original :

Primeiro: como já foi dito, a melhor opção é adicionar uma chave primária à tabela. Ponto final. Se você puder fazer isso, não leia mais.

Mas se você não pode, ou simplesmente se odeia, há uma maneira de fazer isso sem a chave primária.

No meu caso, eu estava trabalhando com um sistema legado (originalmente arquivos simples em um AS400 portado para o Access e, em seguida, portado para o T-SQL). Então eu tive que encontrar uma maneira. Esta é a minha solução. O seguinte funcionou para mim usando o Entity Framework 6.0 (o mais recente no NuGet até o momento desta redação).

  1. Clique com o botão direito do mouse no seu arquivo .edmx no Gerenciador de Soluções. Escolha "Abrir com ..." e selecione "Editor de XML (texto)". Vamos editar manualmente o código gerado automaticamente aqui.

  2. Procure uma linha como esta:
    <EntitySet Name="table_name" EntityType="MyModel.Store.table_name" store:Type="Tables" store:Schema="dbo" store:Name="table_nane">

  3. Retire store:Name="table_name"do final.

  4. Mude store:Schema="whatever"paraSchema="whatever"

  5. Olhe abaixo dessa linha e encontre a <DefiningQuery>tag. Ele terá uma grande e velha declaração de seleção. Remova a tag e seu conteúdo.

  6. Agora sua linha deve ficar assim:
    <EntitySet Name="table_name" EntityType="MyModel.Store.table_name" store:Type="Tables" Schema="dbo" />

  7. Temos mais alguma coisa para mudar. Acesse seu arquivo e encontre o seguinte:
    <EntityType Name="table_name">

  8. Nas proximidades, você provavelmente verá um texto comentado avisando que ela não possui uma chave primária identificada; portanto, a chave foi inferida e a definição é uma tabela / exibição somente leitura. Você pode deixá-lo ou excluí-lo. Eu deletei.

  9. Abaixo está a <Key>tag. É isso que o Entity Framework usará para inserir / atualizar / excluir. ASSIM TENHA CERTEZA DE FAZER ISSO DIREITO. A propriedade (ou propriedades) nessa tag precisa indicar uma linha identificável exclusivamente. Por exemplo, digamos que eu saiba que minha mesa orders, embora não tenha uma chave primária, garante apenas um número de pedido por cliente.

Então o meu se parece com:

<EntityType Name="table_name">
              <Key>
                <PropertyRef Name="order_numbers" />
                <PropertyRef Name="customer_name" />
              </Key>

Sério, não faça isso errado. Digamos que, embora nunca deva haver duplicatas, de alguma forma duas linhas entram no meu sistema com o mesmo número de pedido e nome do cliente. Opa! É isso que recebo por não usar uma chave! Então, eu uso o Entity Framework para excluir um. Como sei que a duplicata é a única ordem feita hoje, faço o seguinte:

var duplicateOrder = myModel.orders.First(x => x.order_date == DateTime.Today);
myModel.orders.Remove(duplicateOrder);

Adivinha? Acabei de excluir a duplicata e o original! Isso porque eu disse ao Entity Framework que order_number / cutomer_name era minha chave primária. Então, quando eu disse para remover duplicateOrder, o que ele fez em segundo plano foi algo como:

DELETE FROM orders
WHERE order_number = (duplicateOrder's order number)
AND customer_name = (duplicateOrder's customer name)

E com esse aviso ... agora você deve ir!

Pharylon
fonte
Encontrei esta resposta depois de encontrar a mesma solução para o problema. Definitivamente a resposta correta! Apenas definir uma chave primária, como mencionado em outras respostas, não ajudará em muitos casos.
Obl Tobl
19

Isso também pode acontecer se o modelo de dados estiver desatualizado.

Espero que isso salve a frustração de alguém :)

mob1lejunkie
fonte
6

Eu estava recebendo a mesma mensagem de erro, mas no meu cenário estava tentando atualizar entidades derivadas de um relacionamento muitos-para-muitos usando uma PJT (Pure Join Table).

Ao ler as outras postagens, pensei em corrigi-lo adicionando um campo PK adicional à tabela de junção ... No entanto, se você adicionar uma coluna PK a uma tabela de junção, ele não será mais um PJT e você perderá todo o vantagens da estrutura da entidade, como o mapeamento automático de relacionamento entre as entidades.

Portanto, a solução no meu caso foi alterar a tabela de junção no banco de dados para criar uma PK que inclua AMBAS as colunas de identificação estrangeira.

Kerry Randolph
fonte
É assim que a geração do EDMX sempre funcionou? Estou acostumado a trabalhar com o Code First, que não requer um PK em uma tabela de junção pura.
Michael Hornfeck
4

pode ocorrer um erro, se sua tabela não tiver chave primária, nesse caso, a tabela é "somente leitura" e o comando db.SaveChanges () sempre trará um erro

Ruben.sar
fonte
4

Defina Chave Primária, salve a Tabela e Atualize, vá para Model.edmx, exclua a Tabela e obtenha novamente.

Ali Raza
fonte
3

então é verdade, basta adicionar uma chave primária

Nota: verifique se, ao atualizar seu diagrama EF do banco de dados que está apontando para o banco de dados correto , no meu caso, a cadeia de conexão estava apontando para um banco de dados local em vez do Dev DB atualizado, estudante erro eu sei, mas eu queria postar isso porque pode ser muito frustrante se você estiver convencido de que adicionou a chave primária e ainda está recebendo o mesmo erro

Spyder
fonte
2

Eu tive o mesmo problema. Como esse thread dizia, Minha tabela não tinha um PK, então configurei o PK e executei o código. Mas, infelizmente, o erro veio novamente. O que eu fiz a seguir foi, excluiu a conexão do banco de dados (exclua o arquivo .edmx na pasta Modelo do Solution Explorer) e a recriei. Erro desaparecido depois disso. Obrigado a todos por compartilhar suas experiências. Economiza muito tempo.

Namal
fonte
1

Eu estava recebendo esse problema porque estava gerando meu EDMX a partir de um banco de dados existente (projetado por outra pessoa e uso o termo 'projetado' livremente aqui).

Acontece que a mesa não tinha chaves. A EF estava gerando o modelo com várias chaves múltiplas. Eu tive que adicionar uma chave primária à tabela db no SQL e atualizei meu modelo no VS.

Isso consertou para mim.

Rígido
fonte
1

Esta não é uma resposta nova, mas ajudará alguém que não tem certeza de como definir a chave primária para sua tabela. Use isso em uma nova consulta e execute. Isso definirá a coluna UniqueID como chave primária.

USE [YourDatabaseName]
GO

Alter table  [dbo].[YourTableNname]
Add Constraint PK_YourTableName_UniqueID Primary Key Clustered (UniqueID);
GO
JessS
fonte
1

insira a descrição da imagem aqui

No meu caso, esqueci de definir a chave primária na tabela. Portanto, atribua como mostrado na Figura e atualize sua tabela em "Atualizar modelo do banco de dados" no arquivo .edmx. Espero que ajude !!!

Yogesh Dangre
fonte
0

Adicionar a chave primária também funcionou para mim!

Feito isso, veja como atualizar o modelo de dados sem excluí-lo -

Clique com o botão direito do mouse na página do designer de entidades edmx e em 'Atualizar modelo do banco de dados'.

Abhishek Poojary
fonte
0

Eu tive exatamente o mesmo problema, infelizmente, adicionar a chave primária não resolve o problema. Então, aqui está como eu resolvo o meu:

  1. Certifique-se de ter um primary keyna mesa, para alterar minha tabela e adicionar uma chave primária.
  2. Delete the ADO.NET Entity Data Model (arquivo edmx) onde uso para mapear e conectar-me ao meu banco de dados.
  3. Add again a new file of ADO.NET Entity Data Model para conectar-se ao meu banco de dados e mapear as propriedades do meu modelo.
  4. Clean and rebuild the solution.

Problema resolvido.

Willy David Jr
fonte
0

basta adicionar uma chave primária à sua mesa e recriar seu EF

Sulyman
fonte
0

Eu apenas tive que remover a tabela do modelo e atualizá-lo novamente, trazendo a tabela de volta. Eu acho que a chave primária foi criada depois que a tabela foi inserida no modelo.

dangalg
fonte
0

Eu tive esse problema e acredito que foi causado porque havia excluído o índice na chave primária de minhas tabelas e substituído por um índice em alguns dos outros campos da tabela.

Depois de excluir o índice de chave primária e atualizar o edmx, as inserções pararam de funcionar.

Atualizei a tabela para a versão mais antiga, atualizei o edmx e tudo funcionou novamente.

Devo observar que quando abri o EDMX para solucionar esse problema, verificando se havia uma chave primária definida. Portanto, nenhuma das sugestões acima estava me ajudando. Mas atualizar o índice na chave primária parecia funcionar.

armstb01
fonte
0

Abra o arquivo .edmx no editor XML e remova a tag da Tag e também altere o armazenamento: Schema = "dbo" para Schema = "dbo" e reconstrua a solução agora, o erro será resolvido e você poderá salvar os dados.

Sharad Tiwari
fonte
0

Eu achei a resposta original de atualizar o arquivo .edmx funcionar melhor na minha situação. Eu simplesmente não estava muito feliz em alterar o modelo toda vez que ele era atualizado no banco de dados. É por isso que escrevi um arquivo de modelo de texto adicional, que é automaticamente invocado quando o modelo é alterado - assim como as entidades são geradas recentemente. Coloco aqui neste comentário. Para que funcione, certifique-se de nomeá-lo como {nome do modelo} .something.tt e armazene-o na mesma pasta que a sua pasta .edmx. Eu o nomeei {nome do modelo} .NonPkTables.tt. Ele não gera um arquivo sozinho devido à definição de extensão de arquivo inválida na segunda linha. Sinta-se livre para usar.

<#@ template language="C#" debug="false" hostspecific="true"#>
<#@ output extension="/" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Data" #>
<#@ assembly name="System.Windows.Forms" #>
<#@ assembly name="System.Xml" #>
<#@ assembly name="System.Xml.Linq"#>
<#@ assembly name="%VS120COMNTOOLS%..\IDE\EntityFramework.dll" #>
<#@ assembly name="%VS120COMNTOOLS%..\IDE\Microsoft.Data.Entity.Design.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Windows.Forms" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Xml.Linq" #>
<#@ import namespace="System.Globalization" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Data.Entity.Core.Metadata.Edm" #>
<#@ import namespace="System.Data.Entity.Core.Mapping" #>
<#@ import namespace="System.CodeDom" #>
<#@ import namespace="System.CodeDom.Compiler" #>
<#@ import namespace="Microsoft.CSharp"#>
<#@ import namespace="System.Text"#>
<#@ import namespace="System.Diagnostics" #>

<#
    string modelFileName= this.Host.TemplateFile.Split('.')[0] + ".edmx";
    string edmxPath = this.Host.ResolvePath( modelFileName );

    // MessageBox.Show( this.Host.TemplateFile + " applied." );
    var modelDoc = XDocument.Load(edmxPath);
    var root = modelDoc.Root;
    XNamespace nsEdmx = @"http://schemas.microsoft.com/ado/2009/11/edmx";
    XNamespace ns = @"http://schemas.microsoft.com/ado/2009/11/edm/ssdl";

    var runtime = root.Elements(nsEdmx + "Runtime").First();
    var storageModels = runtime.Elements(nsEdmx + "StorageModels").First();
    XNamespace nsStore = @"http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator";

    var schema = storageModels.Elements(ns + "Schema").First();
    XNamespace nsCustomAnnotation = @"http://schemas.microsoft.com/ado/2013/11/edm/customannotation";

    var entityTypes = schema.Nodes().OfType<XComment>().Where(c => c.Value.Contains("warning 6002: The table/view"));
    bool changed = false;

    foreach (var node in entityTypes)
    {
        var element = node.ElementsAfterSelf().First();
        string entityName = element.Attribute("Name").Value;

        // Find EntitySet in EntityContainer.
        var entityContainer = schema.Elements(ns + "EntityContainer").First();
        var entitySet = entityContainer.Elements(ns + "EntitySet").First(s => s.Attribute("Name").Value == entityName);

        // Change "store:Schema" attribute to "Schema" attribute.
        var attribute = entitySet.Attribute(nsStore + "Schema");

        if (attribute != null)
        {
            string schemaName = entitySet.Attribute(nsStore + "Schema").Value;
            entitySet.Attribute(nsStore + "Schema").Remove();
            entitySet.Add(new XAttribute("Schema", schemaName));
            changed |= true;
        }

        // Remove the DefiningQuery element.
        var definingQuery = entitySet.Element(ns + "DefiningQuery");

        if (definingQuery != null)
        {
            definingQuery.Remove();
            changed |= true;        
            Debug.WriteLine(string.Format("Removed defining query of EntitySet {0}.", entityName));
        }
    }

    if (changed)
        modelDoc.Save(edmxPath);
#>
Arno Tolmeijer
fonte
-1

Eu enfrentei a mesma mensagem de erro para inserir um registro em uma tabela com a relação muitos-para-muitos . Meu esquema de banco de dados era:

Student (Id , Name)
Course (Code , Title),
Student-Course (Student_ID, Course_Code)

O Aluno e o Curso da tabela possuem as chaves primárias Id e Código , respectivamente , enquanto a tabela Aluno-Curso possui duas chaves estrangeiras mapeadas com as tabelas do aluno e do curso.

Logicamente, o esquema está correto, mas eu estava cometendo um erro no banco de dados, porque todas as tabelas devem ter uma chave primária.

Minha definição sql para Student-Course era:

CREATE TABLE [dbo].[Student-Course] (
    [StudentID]  VARCHAR (12) NOT NULL,
    [CourseCode] VARCHAR (10) NOT NULL,
    CONSTRAINT [FK_Student-Course_ToCourse] FOREIGN KEY ([Course_Code]) REFERENCES [dbo].[Course] ([Code]) ON DELETE CASCADE,
    CONSTRAINT [FK_Student-Course_ToStudent] FOREIGN KEY ([Student_ID]) REFERENCES [dbo].[Student] ([Id]) ON DELETE CASCADE
);

Eu criei o par de chaves estrangeiras a chave primária desta tabela e atualizei para:

CREATE TABLE [dbo].[Student-Course] (
    [StudentID]  VARCHAR (12) NOT NULL,
    [CourseCode] VARCHAR (10) NOT NULL,
    CONSTRAINT [PK_Student-Course] PRIMARY KEY CLUSTERED ([Student_ID] ASC, [Course_Code] ASC),
    CONSTRAINT [FK_Student-Course_ToCourse] FOREIGN KEY ([Course_Code]) REFERENCES [dbo].[Course] ([Code]) ON DELETE CASCADE,
    CONSTRAINT [FK_Student-Course_ToStudent] FOREIGN KEY ([Student_ID]) REFERENCES [dbo].[Student] ([Id]) ON DELETE CASCADE
);

Espero que isso resolva problemas para alguns caras.

Summar Raja
fonte
Esta pergunta já tem muitas respostas. Além disso, quase cada resposta diz "adicione uma chave primária" e uma é feita no contexto de muitos para muitos.
Gert Arnold
Você está certo, mas algumas pessoas adicionam um ID de chave primária extra na terceira tabela, o que não é uma boa abordagem.
Summar Raja
Como a outra resposta também diz.
Gert Arnold