DefiningQuery и в элементе <ModificationFunctionMapping>отсутствует элемент <DeleteFunction>для поддержки текущей операции - PullRequest
11 голосов
/ 30 декабря 2011

Невозможно обновить EntitySet 'InstanceObjectName', так как он имеет DefiningQuery и в элементе нет элемента для поддержки текущей операции

Ответы [ 3 ]

25 голосов
/ 31 марта 2012

Убедитесь, что на вашем столе есть первичный ключ!

4 голосов
/ 30 декабря 2011

Платформа Entity Framework не знает, является ли данное представление обновляемым или нет, поэтому оно добавляет элемент, чтобы обезопасить себя от попытки каркаса генерировать запросы против не обновляемого представления.

Есливаше представление обновляется, вы можете просто удалить элемент из определения EntitySet для вашего представления в разделе StorageModel вашего .edmx, и обычная обработка обновлений будет работать как с любой другой таблицей.

Если ваше представление не может быть обновлено, вам придется самостоятельно предоставить логику обновления через «Отображение функции модификации».Сопоставление функций модификации вызывает функцию, определенную в разделе StorageModel вашего .edmx.Эта функция может содержать имя и аргументы хранимой процедуры в вашей базе данных, или вы можете использовать «определяющую команду», чтобы написать оператор вставки, обновления или удаления непосредственно в определении функции в разделе StorageModel вашего .edmx..

Из двух вариантов, если ваше представление является обновляемым (как это может звучать), проще всего, конечно, удалить вставленное конструктором.

3 голосов
/ 14 февраля 2014

ОБНОВЛЕНИЕ: В последнее время я получил несколько голосов по этому поводу, поэтому я решил, что дам людям знать, что совет, который я даю ниже, не самый лучший. С тех пор как я начал заниматься созданием 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. Это позволит вам делать вставки, обновления и т. Д. На вашей таблице ключей.

Если вы не слишком знакомы с выполнением обратного Code First, найдите хорошее руководство по Entity Framework Code First. Затем, как только вы освоитесь с этим, перейдите на страницу «Обратный код сначала» (которая выполняет «Сначала код» с существующей базой данных). Тогда просто возвращайся сюда и посмотри на мой ключевой совет снова. :)

Оригинальный ответ :

Во-первых: как уже говорили другие, лучший вариант - добавить первичный ключ в таблицу. Полная остановка. Если вы можете сделать это, не читайте дальше.

Но если вы не можете или просто ненавидите себя, есть способ сделать это без первичного ключа. По сути, мы собираемся обмануть Entity Framework и сказать ему, что есть первичный ключ.

В моем случае я работал с устаревшей системой (изначально плоские файлы на 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>. В нем будет большой старый выбор. Удалите тег и его содержимое.

  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 был моим основным ключом. Поэтому, когда я сказал ему удалить duplicateOrder, то, что он делал в фоновом режиме, было что-то вроде:

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

И с этим предупреждением ... теперь вам нужно идти!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...