Член "X" был изменен, чтобы не соответствовать члену ассоциации "Y",
Я получаю эту ошибку, если я выполняю следующие действия:
- Измените свойство Y объекта (связанное свойство объекта)
- Попытка представить изменения
- В этот момент значение Y и значение X (базовый ключ) не согласуются - LINQ to SQL, по-видимому, не синхронизирует их до тех пор, пока не будет вызван GetChangeSet.
- Ожидаемая ошибка возникает из-за некоторых ограничений бизнес-логики или уровня базы данных во время операции обновления.
- В этот момент значение Y согласуется с X, потому что был вызван GetChangeSet.
- Измените значение Y на Nothing (aka null).
- Вызвать GetChangeSet.
Ошибка возникает на последнем шаге, потому что значение X и исходное значение X (возвращено GetOriginalEntityState) различны, а новое значение не согласуется с Y? Вот почему? Это ошибка в LINQ to SQL. Должно быть потому, что я не вижу такого же поведения, если вместо Y вместо Y вместо другого изменить значение (не нулевое). Каков правильный путь? Я вижу несколько способов:
- Отбросить DataContext при возникновении ошибки и оставить UI as-is. Мне это не нравится, потому что оптимистические конфликты с изменением коллаборации не могут быть обнаружены. Новый контекст не имеет исходных значений, которые были заполнены в то же время, когда пользовательский интерфейс был заполнен, поэтому, если в пользовательском интерфейсе есть какие-то устаревшие значения, они приведут к возврату данных в базе данных.
- Обновите datacontext (OverwriteCurrent) и оставьте пользовательский интерфейс как есть. Мне не нравится это по той же причине, что и # 1.
- Обновите datacontext (OverwriteCurrent) и повторно заполните пользовательский интерфейс. Мне это не нравится, потому что сообщение об ошибке, только что представленное пользователю, не показывает пользователю ошибку, которую они сделали, и позволяет им исправить ее. Он также отбрасывает все другие изменения, которые пользователь мог сделать.
- При возникновении ошибки явным образом извлекаю ключ для Y, который соответствует исходному значению X и reset Y, затем вызывает GetChangeSet для повторной синхронизации X (X доступен только для чтения или закрыт, поэтому я не могу reset он напрямую). Это похоже на работу, но похоже на хак и может потребовать много кода для других подобных ошибок.
Есть ли лучшее решение. Это что-то, о чем следует сообщить?
Ответы
Ответ 1
Похоже, эта ошибка была исправлена в последней версии .NET и/или Visual Studio 2010. Код, сгенерированный для файла DBML, теперь содержит код для обновления базового значения внешнего ключа, даже если значение свойства ассоциации равно null:
[global::System.Data.Linq.Mapping.AssociationAttribute(Name="Customer_Order", Storage="_Customer", ThisKey="fkCustomer", OtherKey="id", IsForeignKey=true)]
public Customer Customer
{
get
{
return this._Customer.Entity;
}
set
{
Customer previousValue = this._Customer.Entity;
if (((previousValue != value)
|| (this._Customer.HasLoadedOrAssignedValue == false)))
{
this.SendPropertyChanging();
if ((previousValue != null))
{
this._Customer.Entity = null;
previousValue.Orders.Remove(this);
}
this._Customer.Entity = value;
if ((value != null))
{
value.Orders.Add(this);
this._fkCustomer = value.id;
}
else
{
this._fkCustomer = default(Nullable<int>);
}
this.SendPropertyChanged("Customer");
}
}
}
Я думаю, что this._fkCustomer = default(Nullable<int>);
, должно быть, не было в коде, который я тестировал, когда я изначально разместил этот вопрос. Так что либо я неправильно настроил свой DBML, либо эта проблема была исправлена.
Ответ 2
В MSDN:
Для обновлений отношений ссылка на дочерние элементы родителя (то есть ссылка, соответствующая внешнему ключу) считается авторитетом. Ссылка в обратном направлении (то есть от родителя к дочерней) является необязательной. Классы отношений (EntitySet и EntityRef) гарантируют согласованность двунаправленных ссылок для отношений "один ко многим" и "один к одному". Если объектная модель не использует EntitySet или EntityRef, и если обратная ссылка присутствует, вы несете ответственность за ее соответствие с прямой ссылкой при обновлении отношений.
Если вы обновите требуемую ссылку и соответствующий внешний ключ, вы должны убедиться, что они согласны. Исключение InvalidOperationException генерируется, если они не синхронизируются в то время, когда вы вызываете SubmitChanges. Хотя изменения значения внешнего ключа достаточны для влияния на обновление базовой строки, вы должны изменить ссылку, чтобы поддерживать связь графика объекта и двунаправленную согласованность отношений.
http://msdn.microsoft.com/en-us/library/Bb386982(v=VS.90).aspx
Ответ 3
Недавно я столкнулся с этой проблемой, используя linq для sql, мои классы, которые были сгенерированы с помощью sqlmetal, и отображались с использованием привязок WPF.
При отображении combox значений из таблицы у меня была ссылка с внешним ключом, я устанавливал SelectedValuePath в ID. Однако, когда идентификатор был обновлен в моей записи, связанный элемент не был обновлен, чтобы соответствовать значению ИД.
(Address.provID будет равен 1 и Address.Province будет null)
Я обновил привязку, чтобы обновить SelectedItem, а не SelectedValuePath.
<ComboBox Name="provList" DisplayMemberPath="Code" ItemsSource="{Binding Source={x:Static list:GlobalList.ProvinceList}}" SelectedItem="{Binding Path=Provinces}" Width="75" Height="23" HorizontalAlignment="Left" Margin="5,0,0,0" VerticalAlignment="Top"/>