Impossible de mettre à jour l'EntitySet - car il a un DefiningQuery et aucun élément <UpdateFunction> n'existe

534

J'utilise Entity Framework 1 avec .net 3.5.

Je fais quelque chose de simple comme ça:

var roomDetails = context.Rooms.ToList();

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

Je reçois cette erreur lorsque j'essaie de faire:

 context.SaveChanges();

Je reçois l'erreur:

Impossible de mettre à jour l'EntitySet - car il a un DefiningQuery et aucun élément <UpdateFunction> n'existe dans l'élément <ModificationFunctionMapping> pour prendre en charge l'opération en cours.

Je fais beaucoup de mises à jour sur le contexte et je n'ai aucun problème, c'est uniquement lorsque j'essaie de mettre à jour cette entité particulière.

Toutes mes recherches montrent la même chose, qu'il n'y a pas de clé primaire déclarée sur l'entité que j'essaie de mettre à jour. Mais hélas, j'ai une clé primaire déclarée ...

iKode
la source
61
J'ai fait une erreur, il n'y avait pas de clé primaire sur la table, merci pour votre temps! Désolé pour le dérangement!
iKode
1
Je viens de m'arriver - j'ai probablement créé 1000 tables avec des clés primaires et j'en ai oublié une - le message d'exception n'aide pas beaucoup
Peter Munnings
1
excellent. j'ai vraiment oublié d'ajouter la clé primaire à la table. Essayons d'être prudents)
AEMLoviji

Réponses:

1024

Cela se produit généralement pour l'une des raisons suivantes:

  • L'ensemble d'entités est mappé à partir de la vue Base de données
  • Une requête de base de données personnalisée
  • La table de base de données n'a pas de clé primaire

Après cela, vous devrez peut-être toujours mettre à jour dans le concepteur Entity Framework (ou bien supprimer l'entité puis l'ajouter) avant d'arrêter d'obtenir l'erreur.

Ladislav Mrnka
la source
2
Assurez-vous également de changer store: Schema pour simplement Schema pour cet EntitySet, si vous rencontrez toujours des problèmes.
Geoff
53
Ensuite, supprimez et recréez l'entité car la mise à jour ne fonctionne pas directement dans le concepteur EF.
Suncat2000
48
PK était la réponse. Merci!
nrod
1
La mise à jour dans le concepteur EF a bien fonctionné pour moi après avoir ajouté la clé primaire à la base de données. Utilisation d'EF 5.0 et .net 4.0
StillLearnin
1
Pareil ici ! Thx ... a dû retirer la table et l'ajouter à EF pour qu'elle prenne bien
ajzeffer
90

Ajoutez simplement une clé primaire à la table. C'est ça. Problème résolu.

ALTER TABLE <TABLE_NAME>
ADD CONSTRAINT <CONSTRAINT_NAME> PRIMARY KEY(<COLUMN_NAME>)
Jebastin J
la source
13
et n'oubliez pas de cliquer sur "Mettre à jour le modèle à partir de la base de données" sur votre fichier .edmx
Bashar Abu Shamaa
@BasharAbuShamaa cette réponse n'est pas valable sans ce détail.
Kehlan Krumme
66

C'est le cas pour moi. La simple suppression a entraîné une autre erreur. J'ai suivi les étapes de ce post sauf le dernier. Pour votre commodité, j'ai copié les 4 étapes du message que j'ai suivi pour résoudre le problème comme suit:

  1. Faites un clic droit sur le fichier edmx, sélectionnez Ouvrir avec, éditeur XML
  2. Recherchez l'entité dans l'élément edmx: StorageModels
  3. Supprimer complètement la DefiningQuery
  4. Renommez le store:Schema="dbo"en Schema="dbo"(sinon, le code générera une erreur disant que le nom n'est pas valide)
kavitha Reddy
la source
Merci beaucoup - c'est exactement ce qui a résolu mon problème. Assez inquiétant que cela n'ait pas été corrigé dans EF. Et, assez étonnant que vous ayez compris cela!
Vélo Dave
J'ai essayé de supprimer l'entité et de la rajouter. Recompilation. Nettoyage. Rien n'a fonctionné pour moi sauf cela.
vintastic
1
Cela a résolu mon problème, mais je ne sais pas comment vous avez trouvé des réponses et pourquoi votre suggestion a résolu le problème.
swcraft
Que se passe-t-il si vous devez mettre à jour le modèle de base de données? J'ai fait un "modèle de mise à jour de la base de données" et il a laissé mon modèle totalement inutilisable. J'ai dû annuler et recommencer. S'il y a un moyen de contourner cela?
Gary
C'est un problème vraiment bizarre. Existe-t-il des informations sur la façon dont ce problème se produit afin de l'éviter? Néanmoins - cela a aidé
r3dst0rm
41

Notez simplement que votre entité a peut- être une clé primaire mais que votre table dans la base de données n'a pas de clé primaire .

Majid
la source
1
Comment surmonter, si nous ne pouvons pas changer la table de base de données?
Kai Hartmann
Si vous pouvez modifier la table DB pour avoir une clé primaire, le générateur de code cessera de faire les mêmes erreurs, la suppression de la clé d'EF entraînera de nombreux autres problèmes.
Chris Schaller
30

MISE À JOUR: J'ai reçu quelques votes positifs à ce sujet ces derniers temps, alors j'ai pensé que je ferais savoir aux gens que les conseils que je donnais ci-dessous n'étaient pas les meilleurs. Depuis que j'ai commencé à travailler avec Entity Framework sur d'anciennes bases de données sans clé, je me suis rendu compte que la meilleure chose que vous puissiez faire BY FAR est de le faire en inversant le code en premier. Il existe quelques bons articles sur la façon de procéder. Il vous suffit de les suivre, puis lorsque vous souhaitez y ajouter une clé, utilisez des annotations de données pour "truquer" la clé.

Par exemple, disons que je connais ma table Orders, même si elle n'a pas de clé primaire, est assuré de n'avoir qu'un seul numéro de commande par client. Puisque ce sont les deux premières colonnes de la table, je configurerais les premières classes de code pour ressembler à ceci:

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

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

En faisant cela, vous faîtes essentiellement croire à EF qu'il existe une clé en cluster composée de OrderNumber et de Customer. Cela vous permettra de faire des insertions, des mises à jour, etc. sur votre table sans clé.

Si vous n'êtes pas trop familier avec le code inversé en premier, allez trouver un bon didacticiel sur le code Entity Framework en premier. Ensuite, allez en trouver un sur Reverse Code First (qui fait Code First avec une base de données existante). Revenez ensuite ici et regardez à nouveau mes conseils clés. :)

Réponse originale :

Premièrement: comme d'autres l'ont dit, la meilleure option consiste à ajouter une clé primaire à la table. Arrêt complet. Si vous pouvez le faire, ne lisez pas plus loin.

Mais si vous ne pouvez pas, ou simplement vous détestez, il existe un moyen de le faire sans la clé primaire.

Dans mon cas, je travaillais avec un système hérité (à l'origine des fichiers plats sur un AS400 porté sur Access puis porté sur T-SQL). J'ai donc dû trouver un moyen. C'est ma solution. Ce qui suit a fonctionné pour moi en utilisant Entity Framework 6.0 (la dernière sur NuGet à ce jour).

  1. Cliquez avec le bouton droit sur votre fichier .edmx dans l'Explorateur de solutions. Choisissez "Ouvrir avec ..." puis sélectionnez "Editeur XML (texte)". Nous allons modifier manuellement le code généré automatiquement ici.

  2. Recherchez une ligne comme celle-ci:
    <EntitySet Name="table_name" EntityType="MyModel.Store.table_name" store:Type="Tables" store:Schema="dbo" store:Name="table_nane">

  3. Retirez store:Name="table_name"de la fin.

  4. Remplacer store:Schema="whatever"parSchema="whatever"

  5. Regardez en dessous de cette ligne et trouvez la <DefiningQuery>balise. Il aura une grosse déclaration de sélection en elle. Retirez la balise et son contenu.

  6. Maintenant, votre ligne devrait ressembler à ceci:
    <EntitySet Name="table_name" EntityType="MyModel.Store.table_name" store:Type="Tables" Schema="dbo" />

  7. Nous avons autre chose à changer. Parcourez votre dossier et trouvez ceci:
    <EntityType Name="table_name">

  8. À proximité, vous verrez probablement du texte commenté vous avertissant qu'aucune clé primaire n'a été identifiée, la clé a donc été déduite et la définition est une table / vue en lecture seule. Vous pouvez le laisser ou le supprimer. Je l'ai effacé.

  9. Ci-dessous est la <Key>balise. C'est ce qu'Entity Framework va utiliser pour insérer / mettre à jour / supprimer. ASSUREZ-VOUS DE FAIRE CE DROIT. La ou les propriétés de cette balise doivent indiquer une ligne identifiable de manière unique. Par exemple, disons que je connais ma table orders, même si elle n'a pas de clé primaire, est assuré de n'avoir qu'un seul numéro de commande par client.

Donc le mien ressemble à:

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

Sérieusement, ne faites pas cela mal. Disons que même s'il ne doit jamais y avoir de doublons, d'une manière ou d'une autre, deux lignes pénètrent dans mon système avec le même numéro de commande et le même nom de client. Whooops! C'est ce que j'obtiens pour ne pas utiliser de clé! J'utilise donc Entity Framework pour en supprimer un. Parce que je sais que le duplicata est la seule commande passée aujourd'hui, je fais ceci:

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

Devine quoi? Je viens de supprimer le double ET l'original! C'est parce que j'ai dit à Entity Framework que order_number / cutomer_name était ma clé primaire. Donc, quand je lui ai dit de supprimer duplicateOrder, ce qu'il a fait en arrière-plan était quelque chose comme:

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

Et avec cet avertissement ... vous devriez maintenant être prêt à partir!

Pharylon
la source
Trouvé cette réponse après avoir trouvé la même solution au problème. Certainement la bonne réponse! Seule la définition d'une clé primaire comme mentionné dans d'autres réponses n'aidera pas dans de nombreux cas.
Obl Tobl
19

Cela peut également se produire si le modèle de données est obsolète.

Espérons que cela sauvera la frustration de quelqu'un d'autre :)

mob1lejunkie
la source
6

J'obtenais le même message d'erreur, mais dans mon scénario, j'essayais de mettre à jour des entités dérivées d'une relation plusieurs à plusieurs à l'aide d'un PJT (Pure Join Table).

En lisant les autres articles, j'ai pensé que je pouvais le corriger en ajoutant un champ PK supplémentaire à la table de jointure ... Cependant, si vous ajoutez une colonne PK à une table de jointure, ce n'est plus un PJT et vous perdez tous les avantages du framework d'entité comme le mappage automatique des relations entre les entités.

Donc, la solution dans mon cas était de modifier la table de jointure sur la base de données pour créer un PK qui inclut les deux colonnes d'ID étranger.

Kerry Randolph
la source
Est-ce ainsi que la génération d'EDMX a toujours fonctionné? J'ai l'habitude de travailler avec Code First qui ne nécessite pas de PK sur une table de jointure pure.
Michael Hornfeck
4

une erreur peut se produire, si votre table n'a pas de clé primaire, dans ce cas la table est en "lecture seule", et la commande db.SaveChanges () apportera toujours une erreur

Ruben.sar
la source
4

Définissez la clé primaire, puis enregistrez la table et actualisez, puis accédez à Model.edmx supprimer la table et obtenez à nouveau.

Ali Raza
la source
3

donc c'est vrai, il suffit d'ajouter une clé primaire

Remarque: assurez-vous que lorsque vous mettez à jour votre diagramme EF à partir de la base de données que vous pointez vers la bonne base de données, dans mon cas, la chaîne de connexion pointait vers une base de données locale au lieu de la base de données de développement à jour, écolier erreur je sais, mais je voulais poster ceci parce que cela peut être très frustrant si vous êtes convaincu que vous avez ajouté la clé primaire et que vous obtenez toujours la même erreur

Spyder
la source
2

J'ai eu le même problème. Comme ce fil l'a dit, Ma table n'avait pas de PK, j'ai donc défini le PK et exécuté le code. Mais malheureusement, l'erreur est revenue. J'ai ensuite supprimé la connexion à la base de données (supprimer le fichier .edmx dans le dossier Model de l'Explorateur de solutions) et la recréer. Erreur disparue après cela. Merci à tous d'avoir partagé vos expériences. Cela fait gagner beaucoup de temps.

Namal
la source
1

J'obtenais ce problème parce que je générais mon EDMX à partir d'une base de données existante (conçue par quelqu'un d'autre, et j'utilise le terme «conçu» librement ici).

Il s'avère que la table n'avait aucune clé. EF générait le modèle avec plusieurs clés multiples. Je devais aller ajouter une clé primaire à la table db en SQL puis mettre à jour mon modèle en VS.

Cela m'a arrangé.

Rigide
la source
1

Ce n'est pas une nouvelle réponse, mais cela aidera quelqu'un qui ne sait pas comment définir la clé primaire de sa table. Utilisez-le dans une nouvelle requête et exécutez. Cela définira la colonne UniqueID comme clé primaire.

USE [YourDatabaseName]
GO

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

entrez la description de l'image ici

Dans mon cas, j'ai oublié de définir la clé primaire de la table. Attribuez donc comme indiqué dans Image et actualisez votre table à partir de "Mettre à jour le modèle à partir de la base de données" du fichier .edmx. J'espère que cela vous aidera !!!

Yogesh Dangre
la source
0

L'ajout de la clé primaire a également fonctionné pour moi!

Une fois cela fait, voici comment mettre à jour le modèle de données sans le supprimer -

Faites un clic droit sur la page du concepteur d'entité edmx et sur «Mettre à jour le modèle à partir de la base de données».

Abhishek Poojary
la source
0

J'ai eu exactement le même problème, malheureusement, l'ajout de la clé primaire ne résout pas le problème. Alors, voici comment je résous le mien:

  1. Assurez-vous que vous avez un primary keysur la table afin que je modifie ma table et ajoute une clé primaire.
  2. Delete the ADO.NET Entity Data Model (fichier edmx) où j'utilise pour mapper et me connecter à ma base de données.
  3. Add again a new file of ADO.NET Entity Data Model pour me connecter à ma base de données et pour mapper mes propriétés de modèle.
  4. Clean and rebuild the solution.

Problème résolu.

Willy David Jr
la source
0

ajoutez simplement une clé primaire à votre table, puis recréez votre EF

Sulyman
la source
0

J'ai juste dû retirer la table du modèle et mettre à jour le modèle en ramenant à nouveau la table. Je suppose que la clé primaire a été créée après que la table a été tirée dans le modèle.

dangalg
la source
0

J'ai eu ce problème et je pense qu'il a été causé parce que j'avais supprimé l'index sur ma clé primaire de tables et l'avais remplacé par un index sur certains des autres champs de la table.

Après avoir supprimé l'index de clé primaire et actualisé l'edmx, les insertions ont cessé de fonctionner.

J'ai actualisé le tableau à l'ancienne version, actualisé l'edmx et tout fonctionne à nouveau.

Je dois noter que lorsque j'ai ouvert l'EDMX pour résoudre ce problème, en vérifiant s'il y avait une clé primaire définie, il y en avait. Aucune des suggestions ci-dessus ne m'a donc aidé. Mais l'actualisation de l'index sur la clé primaire semblait fonctionner.

armstb01
la source
0

Ouvrez votre fichier .edmx dans l'éditeur XML, puis supprimez la balise de la balise et changez également de magasin: Schema = "dbo" en Schema = "dbo" et reconstruisez la solution maintenant, l'erreur se résoudra et vous pourrez enregistrer les données.

Sharad Tiwari
la source
0

J'ai trouvé la réponse originale de la mise à jour du fichier .edmx fonctionner le mieux dans ma situation. Je n'étais tout simplement pas trop content de modifier le modèle à chaque fois qu'il était mis à jour à partir de la base de données. C'est pourquoi j'ai écrit un fichier de modèle de texte supplémentaire, qui est automatiquement invoqué lorsque le modèle a changé - tout comme les entités sont nouvellement générées. Je le poste ici dans ce commentaire. Pour le faire fonctionner, assurez-vous de le nommer comme {nom du modèle} .something.tt et stockez-le dans le même dossier que votre dossier .edmx. Je l'ai nommé {nom du modèle} .NonPkTables.tt. Il ne génère pas de fichier seul en raison de la définition d'extension de fichier non valide dans la deuxième ligne. N'hésitez pas à utiliser.

<#@ 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
la source
-1

J'ai fait face au même message d'erreur pour insérer un enregistrement dans une table ayant une relation plusieurs-à-plusieurs . Mon schéma de base de données était:

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

Table des étudiants et cours ont des clés Id et code respectivement , tandis que la table étudiant-Cours a deux clés étrangères mis en correspondance avec des tables et des étudiants du cours.

Logiquement, le schéma est correct mais je faisais une erreur dans la base de données, car chaque table devrait avoir une clé primaire.

Ma définition sql pour Student-Course était:

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
);

J'ai fait d'une paire de clés étrangères la clé primaire de cette table et mis à jour pour:

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
);

J'espère que cela résoudra les problèmes de certains gars.

Summar Raja
la source
Cette question a déjà beaucoup trop de réponses. De plus, presque chaque réponse dit "ajouter une clé primaire" et on le fait dans le contexte du plusieurs-à-plusieurs.
Gert Arnold
Vous avez raison, mais certaines personnes ajoutent un identifiant de clé primaire supplémentaire dans la troisième table, ce qui n'est pas une bonne approche.
Summar Raja
Comme le dit également l'autre réponse.
Gert Arnold