Неможливо оновити EntitySet - тому що у нього є DefiningQuery і не існує елемента <UpdateFunction>


533

Я використовую Entity Framework 1 з .net 3.5.

Я роблю щось просте на кшталт цього:

var roomDetails = context.Rooms.ToList();

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

Я отримую цю помилку, коли намагаюся зробити:

 context.SaveChanges();

Я отримую помилку:

Неможливо оновити EntitySet - оскільки в ньому є елемент DefiningQuery, а в елементі <ModificationFunctionMapping> не існує елемента <UpdateFunction> для підтримки поточної операції.

Я роблю багато оновлень у контексті і не маю жодних проблем, це лише тоді, коли я намагаюся оновити цю конкретну сутність.

Під час всіх моїх пошуків виявляється одне і те ж, що в об'єкті не оголошено первинного ключа, який я намагаюся оновити. Але на жаль, у мене оголошено Первинний ключ ...


61
Я помилився, на столі не було набору первинного ключа, дякую за ваш час! Вибачте за незручності!
iKode

1
Щойно зі мною трапилось - напевно, створили 1000 таблиць з первинними ключами, і забули один - повідомлення про виняток не дуже допомагає
Пітер Маннінгс

1
відмінна. дійсно я забув додати первинний ключ до таблиці. Спробуймо бути обережними)
AEMLoviji

Відповіді:


1022

Зазвичай це відбувається через одну з наступних причин:

  • Набір сутності відображається з подання бази даних
  • Спеціальний запит до бази даних
  • У таблиці бази даних немає первинного ключа

Після цього вам може знадобитися оновити в дизайнері Entity Framework (або видалити об'єкт і потім додати його), перш ніж перестати отримувати помилку.


2
Не забудьте також змінити магазин: схему на просто схему для цього EntitySet, якщо у вас все ще виникають проблеми.
Джефф

53
Потім видаліть і відтворіть сутність, оскільки оновлення не працює правильно в дизайнері EF.
Suncat2000

48
ПК відповідь. Дякую!
nrod

1
Оновлення в дизайнері EF працювало для мене чудово після додавання Первинного ключа до бази даних. Використання EF 5.0 та .net 4.0
StillLearnin

1
Те ж саме ! Thx ... довелося видалити таблицю та знову додати EF, щоб її взяти, хоча
ajzeffer

90

Просто додайте первинний ключ до таблиці. Це воно. Проблема вирішена.

ALTER TABLE <TABLE_NAME>
ADD CONSTRAINT <CONSTRAINT_NAME> PRIMARY KEY(<COLUMN_NAME>)

13
і не забудьте натиснути на "Оновити модель з бази даних" на вашому .edmx файлі
Башар Абу Шамаа

@BasharAbuShamaa ця відповідь не достовірна без цієї деталі.
Келан Крумме

66

Це справа у мене. Просто видалення призвело до чергової помилки. Я дотримувався кроків цієї публікації, крім останнього. Для вашої зручності я скопіював 4 кроки з публікації, яку я дотримувався, щоб вирішити проблему наступним чином:

  1. Клацніть правою кнопкою миші на файл edmx, виберіть Відкрити за допомогою, редактор XML
  2. Знайдіть об'єкт у елементі edmx: StorageModels
  3. Видаліть DefiningQuery повністю
  4. Перейменуйте store:Schema="dbo"на Schema="dbo"(в іншому випадку код створить помилку, сказавши, що ім’я недійсне)

Дуже дякую - саме це вирішило мою проблему. Дуже тривожно, що це не було зафіксовано в EF. І, дивовижно, що ви це зрозуміли!
Велосипед Дейв

Я спробував видалити об'єкт і повторно додати його. Перекомпіляція. Прибирання. Ніщо не працювало для мене, окрім цього.
вінтастичний

1
Це вирішило моє питання, але я не знаю, як ви придумали відповіді і чому ваша пропозиція вирішила це питання.
swcraft

Що станеться, якщо вам потрібно оновити модель бази даних? Я зробив "Оновлення моделі з бази даних", і це залишило мою модель абсолютно непридатною. Довелося скасувати і почати заново. Якщо є шлях до цього?
Гері

Це дійсно дивне питання. Чи є інформація про те, як виникає ця проблема, щоб її уникнути? Тим не менше - це допомогло
r3dst0rm

41

Зауважте лише, що, можливо, ваш Entity має первинний ключ, але ваша таблиця в базі даних не має первинного ключа .


1
Як подолати, якщо ми не можемо змінити таблицю бази даних?
Кай Хартманн

Якщо ви можете змінити таблицю DB на первинний ключ, тоді генератор коду перестане робити ті самі помилки, вилучення ключа з EF спричинить багато інших проблем.
Кріс

30

ОНОВЛЕННЯ: Останнім часом я отримав кілька оновлень, тому зрозумів, що дам людям поради, які я даю нижче, не найкращий. Оскільки я спочатку почав спілкуватися з тим, щоб робити Entity Framework на старих базах даних без ключів, я зрозумів, що найкраще, що можна зробити BY FAR - це зробити це за допомогою зворотного коду. Існує кілька хороших статей про те, як це зробити. Просто дотримуйтесь їх, а потім, коли ви хочете додати ключ до нього, використовуйте примітки до даних, щоб "підробити" ключ.

Наприклад, скажімо, що я знаю свою таблицю Orders, хоча вона не має первинного ключа, але гарантовано мати лише один номер замовлення на кожного клієнта. Оскільки це перші два стовпці таблиці, я б встановив код перших класів, щоб виглядати так:

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

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

Роблячи це, ви в основному підробляєте EF, що вважає, що існує кластерний ключ, що складається з OrderNumber та Customer. Це дозволить робити вставки, оновлення тощо на вашій таблиці без ключів.

Якщо ви не надто знайомі з тим, як робити зворотний код По-перше, перейдіть і знайдіть хороший підручник з Entity Framework Code. Потім перейдіть до пошуку на Reverse Code First (що робиться Code First із наявною базою даних). Тоді просто поверніться сюди і знову подивіться на мою ключову пораду. :)

Оригінальний відповідь :

По-перше: як говорили інші, найкращий варіант - додати первинний ключ до таблиці. Повна зупинка. Якщо ви можете це зробити, не читайте більше.

Але якщо ви не можете або просто ненавидите себе, є спосіб зробити це без первинного ключа.

У моєму випадку я працював зі застарілою системою (спочатку плоскі файли на AS400, перенесеному в Access, а потім перенесеному на T-SQL). Тому мені довелося знайти спосіб. Це моє рішення. Наступне працювало для мене за допомогою Entity Framework 6.0 (остання версія NuGet станом на цей час).

  1. Клацніть правою кнопкою миші файл .edmx у Провіднику рішень. Виберіть "Відкрити за допомогою ...", а потім виберіть "XML (Text) Editor". Тут ми будемо редагувати вручну автоматично створений код.

  2. Шукайте такий рядок:
    <EntitySet Name="table_name" EntityType="MyModel.Store.table_name" store:Type="Tables" store:Schema="dbo" store:Name="table_nane">

  3. Зніміть store:Name="table_name"з кінця.

  4. Змінити store:Schema="whatever"наSchema="whatever"

  5. Подивіться нижче цього рядка і знайдіть <DefiningQuery>тег. У ньому буде великий оператор select ol 'select. Видаліть тег і його вміст.

  6. Тепер ваша лінія повинна виглядати приблизно так:
    <EntitySet Name="table_name" EntityType="MyModel.Store.table_name" store:Type="Tables" Schema="dbo" />

  7. У нас є щось ще змінити. Перегляньте свій файл і знайдіть це:
    <EntityType Name="table_name">

  8. Поруч, ймовірно, ви побачите якийсь коментований текст, який попереджає вас про те, що в ньому не був визначений первинний ключ, тому ключ був зроблений із висновку, а визначення - це таблиця / перегляд лише для читання. Ви можете залишити його або видалити. Я її видалив.

  9. Нижче - <Key>тег. Це те, що Entity Framework буде використовуватись для вставки / оновлення / видалення. ТО ПЕРЕКОНАЙТЕ, ВИ ВИСТАВЛЯЄТЕ ЦЕ ПРАВО. Властивість (або властивості) у цьому тезі повинні вказувати однозначно ідентифікований рядок. Наприклад, скажімо, що я знаю свою таблицю orders, хоча вона не має первинного ключа, але гарантовано мати лише один номер замовлення на кожного клієнта.

Так моє виглядає так:

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

Серйозно, не робіть цього неправильно. Скажімо, що хоч ніколи не повинно бути дублікатів, якось два ряди потрапляють у мою систему з тим самим номером замовлення та назвою клієнта. Whooops! Ось що я отримую за те, що не користуюся ключем! Тому я використовую Entity Framework для видалення. Оскільки я знаю, що дублікат - це єдине замовлення, яке було зроблено сьогодні, я це роблю:

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

Вгадай що? Я просто видалив як дублікат, так і оригінал! Це тому, що я сказав Entity Framework, що мій основний ключ був order_number / cutomer_name. Тож коли я сказав йому видалити дублікатOrder, те, що було зроблено на задньому плані, було щось на зразок:

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

І з цим попередженням ... вам зараз слід добре піти!


Знайшов цю відповідь, знайшовши те саме рішення проблеми. Однозначно правильна відповідь! Тільки визначення первинного ключа, як згадується в інших відповідях, не допоможе у багатьох випадках.
Обл Тобл

19

Це також може статися, якщо модель даних застаріла.

Сподіваємось, це позбавить когось іншого розчарування :)


6

Я отримував те саме повідомлення про помилку, але в моєму сценарії я намагався оновити об'єкти, отримані від відносин "багато до багатьох", використовуючи PJT (Pure Join Table).

Ознайомившись з іншими публікаціями, я подумав, що зможу це виправити, додавши додаткове поле ПК до таблиці приєднання ... Однак, якщо до таблиці приєднання додати стовпець ПК, це вже не PJT, і ви втратите все переваги рамки сутності, такі як автоматичне відображення відносин між сутностями.

Таким чином, у моєму випадку рішенням було змінити таблицю приєднання в БД, щоб зробити ПК, який включає ВІДБУ стовпців іноземних ідентифікаторів.


Це так, як генерувати EDMX завжди працювало? Я звик працювати з Code First, який не вимагає ПК у чистому таблиці приєднання.
Майкл Хорнфек

4

може статися помилка, якщо у вашій таблиці немає первинного ключа, у цьому випадку таблиця "лише для читання", а команда db.SaveChanges () завжди буде приносити помилку


4

Встановіть первинний ключ, потім збережіть таблицю та оновіть, потім перейдіть до Model.edmx видалити таблицю та знову отримайте.


3

тому його правда, просто додайте первинний ключ

Примітка. Будьте впевнені, що при оновленні діаграми EF з бази даних, на яку ви вказуєте праворуч , в моєму випадку рядок підключення вказував на локальну БД замість оновленої БД Dev, школяр помилка Я знаю, але я хотів опублікувати це, тому що це може бути дуже неприємно, якщо ви впевнені, що ви додали первинний ключ, і ви все ще отримуєте ту саму помилку


2

У мене було те саме питання. Як сказано в цій темі, у моїй таблиці не було ПК, тому я встановив ПК і запустив код. Але на жаль помилка знову прийшла. Потім я видалив підключення до БД (видаліть .edmx файл у папці Модель Провідника Рішення) та відтворив його. Помилка пішла після цього. Дякуємо всім, що поділилися своїм досвідом. Це економить багато часу.


1

У мене виникла ця проблема, тому що я генерував свій EDMX з існуючої бази даних (розроблений кимось іншим, і я тут використовую термін "розроблений").

Виявляється, у таблиці не було жодних ключів. EF генерувала модель з безліччю декількох клавіш. Мені довелося додати первинний ключ до таблиці db в SQL, а потім оновив свою модель в VS.

Це зафіксувало це для мене.


1

Це не нова відповідь, але допоможе тому, хто не впевнений, як встановити первинний ключ для своєї таблиці. Використовуйте це в новому запиті та запустіть. Це встановить колонку UniqueID як основний ключ.

USE [YourDatabaseName]
GO

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

1

введіть тут опис зображення

У моєму випадку забув визначити первинний ключ до таблиці. Тож призначте, як показано на малюнку, та оновіть таблицю з "Оновити модель із бази даних" з файлу .edmx. Сподіваюся, це допоможе !!!


0

Додавання первинного ключа працювало і для мене!

Коли це буде зроблено, ось як оновити модель даних, не видаляючи її -

Клацніть правою кнопкою миші на сторінці дизайнера edmx Entity і виберіть "Оновити модель з бази даних".


0

У мене була та сама проблема, на жаль, додавання первинного ключа не вирішує проблему. Отже, ось як я вирішую своє:

  1. Переконайтеся, що у вас є primary keyна столі, щоб я змінив свою таблицю і додав первинний ключ.
  2. Delete the ADO.NET Entity Data Model (файл edmx), де я використовую для відображення та підключення до своєї бази даних.
  3. Add again a new file of ADO.NET Entity Data Model для підключення до моєї бази даних та для відображення властивостей моєї моделі.
  4. Clean and rebuild the solution.

Проблема вирішена.


0

просто додайте первинний ключ до своєї таблиці, а потім відтворіть свій EF


0

Мені просто довелося вийняти таблицю з моделі та оновити модель, знову повертаючи таблицю. Я думаю, первинний ключ був створений після того, як таблиця була втягнута в модель.


0

У мене виникла ця проблема, і я вважаю, що вона викликана тим, що я видалив індекс з моїх таблиць первинним ключем і замінив його індексом на деяких інших полях таблиці.

Після того, як я видалив індекс первинного ключа та оновив edmx, вставки перестали працювати.

Я оновив таблицю до старшої версії, оновив edmx і все працює знову.

Слід зазначити, що коли я відкрив EDMX для усунення цієї проблеми, перевірив, чи визначений первинний ключ. Тож жодна з перерахованих вище пропозицій мені не допомагала. Але оновлення індексу на первинному ключі, здавалося, працює.


0

Відкрийте файл .edmx у редакторі XML, а потім видаліть тег із тегу, а також змініть store: Schema = "dbo" на Schema = "dbo", і відновіть рішення, тепер помилка вирішиться, і ви зможете зберегти дані.


0

Я знайшов оригінальну відповідь на оновлення роботи файлу .edmx найкраще в моїй ситуації. Я просто не надто задоволений зміною моделі щоразу, коли вона оновлювалася з бази даних. Ось чому я написав додатковий файл текстових шаблонів, який автоматично викликається, коли після зміни моделі - так само, як сутності знову створені. Я публікую його тут, у цьому коментарі. Щоб він працював, переконайтесь, що ви його називаєте як {model name} .something.tt, і зберігайте його в тій самій папці, що і папка .edmx. Я назвав його {ім'я моделі} .NonPkTables.tt. Він не генерує файл самостійно через неправильне визначення розширення файлу у другому рядку. Сміливо користуйтесь.

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

-1

Я зіткнувся з тим же повідомленням про помилку, щоб вставити запис у таблицю, що має відношення " Багато до багатьох" . Моя схема бази даних була:

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

У таблиці Student і Course є первинні ключі Id та Code відповідно , тоді як у таблиці Student-Course є два зовнішні ключі, зіставлені зі таблицями Student та Course.

Логічно, схема правильна, але я робив помилку в базі даних, тому що кожна таблиця повинна мати первинний ключ.

Моє визначення sql для студентського курсу :

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

Я зробив пару іноземних ключів основним ключем цієї таблиці та оновив:

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

Сподіваюся, це вирішить проблеми для деяких хлопців.


На це питання вже є занадто багато відповідей. Більше того, майже у кожній відповіді сказано "додати первинний ключ", і це робиться в контексті "багато-до-багатьох".
Герт Арнольд

Ви маєте рацію, але деякі люди додають додатковий ідентифікатор первинного ключа в третю таблицю, що не є гарним підходом.
Підсумуйте Раджа

Як говорить інша відповідь.
Герт Арнольд
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.