Как я могу установить значение свойства навигации в коде позади? - PullRequest
1 голос
/ 22 августа 2011

У меня есть сущность с именем Cost, которая имеет обязательное свойство CostType

. Класс Cost имеет метод GetNew(), который устанавливает все значения по умолчанию для стоимости:

public static GetNew()
{
    Cost cost = new Cost ();
    foo.CostType = Lists.CostTypes.FirstOrDefault();
    // Other Default Values

    return foo;
}

Lists.CostTypes - это статический список, который извлекается из EF при запуске и используется в ComboBoxes

У меня проблемы с установкой CostType в моем коде после первой установки в методе GetNew().

Например, следующий код читает файл Excel и задает тип по умолчанию на основе столбца в файле Excel, или ноль, если не удается найти совпадение

Cost cost = Cost.GetNew();
cost.CostType = Lists.CostTypes.FirstOrDefault(t => t.Name == row[0].ToString());

Моя проблема в том, что во время операции сохранения я получаю следующую ошибку:

Операция не выполнена: отношение не может быть изменено, так как одно или несколько свойств внешнего ключа не могут быть равны нулю.Когда в отношение вносится изменение, для соответствующего свойства внешнего ключа устанавливается нулевое значение.Если внешний ключ не поддерживает нулевые значения, необходимо определить новое отношение, свойству внешнего ключа должно быть назначено другое ненулевое значение или несвязанный объект должен быть удален.

MyОперация добавления выглядит следующим образом:

public static void AddObject(EntityObject obj, string entitySetName)
{
    context.AddObject(entitySetName, obj);
    context.SaveChanges();
}
  • Если я удаляю строку кода, которая вручную устанавливает стоимость при чтении файла Excel, сохранение работает нормально.
  • Если я изменю строку кода на чтение Lists.Costs [2], это сохранит нормально.
  • Если я удаляю строку кода в GetNew(), которая устанавливает значение по умолчанию, я получаю сообщение об ошибке, сообщающее, что я нарушил правило PK CostTypes, то есть оно пытается вставить тип стоимости.
  • Изменение ComboBox, показывающего тип на что-то другое, все равно вызывает ту же ошибку.
  • После загрузки затрат из файла excel мои обычные формы добавления / редактирования выдают ту же ошибку, когда я изменяю тип и пытаюсь сохранить.Если я не загружаю файл Excel, они работают нормально.

Я все еще изучаю Entity Framework, но до сих пор использовать его было просто разочарованием и головной болью.Кто-нибудь знает, в чем заключается моя проблема и как я могу ее исправить?

РЕДАКТИРОВАТЬ

Вот информация, запрошенная Слаумой.Я держу это простым и исключая несвязанные объекты

  • Costs находятся в одной таблице и CostTypes находятся в другой таблице.В базе данных столбец Costs.TypeId не может быть пустым и является внешним ключом для CostTypes.Поле Id для обеих таблиц генерируется автоматически.

  • Моя модель EF - это просто общая модель с добавлением двух таблиц базы данных.Единственное изменение, которое я внес в него, - это переименовать некоторые поля и удалить CostTypes.Costs Свойство навигации.

  • Файл Excel, который получает импортированные, сопоставляет большинство затрат с их соответствием CostType.Name, однакоВозможно, что строка в файле Excel не соответствует CostType, поэтому Lists.CostTypes.FirstOrDefault(t => t.Name == row[0].ToString()) can assign a NULL value to the Cost.Type property. That doesn't seem to be a problem though, because the form still comes up with the list of costs and their default selected items. Item's with a NULL CostType do not have an item selected in the CostType ComboBox` и вызывают ошибку проверки, которую необходимо исправить перед сохранением.

Код для загрузки списка CostType:

public static List<T> GetList<T>(string sortProperty)
    where T : EntityObject
{
    using (var context = new TContext())
    {
        return ApplyOrder<T>(context.CreateObjectSet<T>(), sortProperty, "OrderBy").ToList();
    }
}

Код ApplyOrder можно найти здесь .

Метод GetList вызывается из

public static class Lists
{
    public static List<CostType> CostTypes { get; private set; }

    static Lists()
    {
        CostTypes = DAL<CostEntities>.GetList<CostType>("Name");
    }
}

Ответы [ 2 ]

2 голосов
/ 23 августа 2011

Я понял это ... это было сочетание нескольких разных вещей

Создание нового Cost и установка Type добавляли стоимость к контексту общих данных.Если эта Стоимость не была включена в список затрат для сохранения или произошла ошибка проверки, или пользователь отменил выход из диалогового окна «Импорт», стоимость все еще существовала в context.ObjectStateManager._addedObjects, хотя я никогда не звонил AddObject илиAttachObject.Однажды я понял, что начал звонить DeleteObject о затратах, которые не собирались экономить, и это очистило 1-ю полученную ошибку.

2-я ошибка, которую я получал (дубликат PK), была из-заперебирая мои новые затраты и вызывая AddObject и SaveChanges на каждом.Так как установка Cost.Type для присоединенного CostType автоматически добавляла мои затраты в контекст, первая сохраненная стоимость фактически добавляла все новые затраты в базу данных, в то время как вторая стоимость пыталась вызвать AddObject / * 1016.* на том, что EF видел как объект, который уже существовал

1 голос
/ 23 августа 2011

Здесь на самом деле не удовлетворительный ответ, а смесь догадок и открытых вопросов, основанных на вашей информации в вопросе и комментариях к вашему вопросу:

  • Прежде всего: Ваш список Lists.CostTypes содержит, очевидно, сущности, которые отделены от контекста, в который вы позже добавляете и сохраняете новые объекты. Поскольку у вас есть блок using: using (var context = new TContext()) вы извлекаете ваши CostType сущности в другом контексте.

  • Чтобы сообщить EF, что эти CostType сущности уже существуют в базе данных, вы должны присоединить сущности ко второму контексту (context.CostTypes.Attach(costType)), где вы сохраняете свои изменения (или используете тот же контекст в вашем методе, где вы получаете список). Я не вижу в вашем коде, что вы делаете это. (CostType это свойство ссылки навигации, а не свойство внешнего ключа, верно?)

  • С другой стороны, когда CostType сущности не присоединены, вы должны получить дубликаты CostTypes в вашей базе данных, потому что EF будет рассматривать их как новые объекты (для вставки в БД), когда вы вызываете AddObject для вашего Cost сущность, поскольку EF всегда переводит весь граф объектов отделенных сущностей в состояние Added. Получаете ли вы дублированные CostTypes в БД в ваших рабочих примерах? Если нет, то в ваших фрагментах кода отсутствует что-то важное.

  • В последнем абзаце предполагается, что ключ для CostType автоматически генерируется в БД, как вы сказали. Если нет, вы получите нарушение ограничения PK вместо дублированных сущностей.

  • Если ключи для CostType и Cost действительно являются автоматически сгенерированными идентификационными данными, мне интересно, откуда может возникнуть упомянутое вами нарушение PK. Каждая вставка создаст новый уникальный первичный ключ. Там никогда не может произойти нарушение PK. Можете ли вы показать сообщение об исключении в деталях?

  • Проверяли ли вы, что все Cost сущности, которые вы хотите сохранить действительно , имеют ненулевое свойство CostType (после того, как пользователь исправил все ошибки проверки)? Я не вижу в вашем коде другой возможной причины, по которой вы получили бы исключение "Отношения не могут быть изменены", за исключением того, что по крайней мере для одного из Cost объектов CostType равен null.

...