成员'X'被更改为与协会成员'Y'不一致

时间:2011-01-03 20:57:25

标签: .net vb.net linq-to-sql

如果我按照以下步骤操作,则会出现此错误:

  1. 更改对象的属性Y(关联的实体属性)
  2. 尝试提交更改
  3. 此时Y的值和X的值(底层键)不一致 - 在调用GetChangeSet之前,LINQ to SQL显然不会同步它们。
  4. 由于更新操作期间的某些业务逻辑或数据库级别约束而发生预期错误。
  5. 此时Y的值与X一致,因为调用了GetChangeSet。
  6. 将Y的值更改为Nothing(也称为null)。
  7. 调用GetChangeSet。
  8. 最后一步发生错误,因为X的值和X的原始值(由GetOriginalEntityState返回)不同,新值与Y不一致?这是为什么?这是LINQ to SQL中的错误。必须是因为如果我在步骤5中将Y更改为另一个(非空)值,我看不到相同的行为。这是正确的方法吗?我可以看到几种方式:

    1. 发生错误时丢弃DataContext并保持UI原样。我不喜欢这个,因为那时乐观的共存货币变化冲突无法被发现。新上下文中没有填充UI时填充的原始值,因此如果UI中有任何过时的值,它们将导致数据库中的数据还原。
    2. 刷新datacontext(OverwriteCurrent)并保持UI原样。我不喜欢这个与#1相同的原因。
    3. 刷新datacontext(OverwriteCurrent)并重新填充UI。我不喜欢这样,因为刚刚呈现给用户的错误消息不会向用户显示他们所犯的错误并允许他们更正错误。它还会丢弃用户可能做出的所有其他更改。
    4. 当错误发生时,显式检索对应于X原始值的Y键并重置Y,然后调用GetChangeSet重新同步X(X是只读或私有的,所以我不能直接重置它)。这似乎有效,但看起来像是一个黑客,并且可能需要大量代码来解决其他类似错误。
    5. 是否有更好的解决方案。这是应该报告的吗?

3 个答案:

答案 0 :(得分:0)

每个MSDN:

对于关系的更新,从子项到父项的引用(即对应于外键的引用)被视为权限。反方向的引用(即从父级到子级)是可选的。关系类(EntitySet和EntityRef)保证双向引用对于一对多和一对一关系是一致的。如果对象模型不使用EntitySet或EntityRef,并且如果存在反向引用,则在更新关系时,您有责任使其与前向引用保持一致。

如果您同时更新了所需的引用和相应的外键,则必须确保它们同意。如果在您调用SubmitChanges时两者未同步,则抛出InvalidOperationException异常。虽然外键值更改足以影响基础行的更新,但您应更改引用以维护对象图的连接性和关系的双向一致性。

http://msdn.microsoft.com/en-us/library/Bb386982(v=VS.90).aspx

答案 1 :(得分:0)

在最新的.NET和/或Visual Studio 2010中修复了此错误。为DBML文件生成的代码现在包含用于更新基础外键值的代码,即使将association属性设置为null也是如此: / p>

    [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 :(得分:0)

我最近使用linq to sql,我的类使用sqlmetal生成并使用WPF绑定显示这个问题。

当我从表中显示一个值的combox时,我有一个外键引用,我将SelectedValuePath设置为ID。但是,当我的记录更新了Id时,关联的成员未更新以匹配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"/>