【问题标题】:Linq-to-Sql SubmitChanges not updating fields ... why?Linq-to-Sql SubmitChanges 不更新字段...为什么?
【发布时间】:2010-09-28 00:34:44
【问题描述】:

我昨天晚上发布了这个question,这让我发现了一个巨大的问题!

我的数据库中有一个名为 Units 的小数列,每当我将该列的值设置为非零时,并且 SubmitChanges 使用新值更新该列。如果我尝试将列的值设置为零,SubmitChanges 不会更新该列。

data.Units = this.ReadProperty<decimal>(UnitsProperty);
data.UnitPrice = this.ReadProperty<decimal>(UnitPriceProperty);
data.Price = this.ReadProperty<decimal>(PriceProperty);

我查看了 DataContext 日志,可以看到具有零值的字段未包含在查询中。即使我尝试对更改进行硬编码,Linq 也会忽略它。

data.Units = 0;
data.UnitPrice = 0;
data.Price = 0;

不用说这是要了我的命!任何想法为什么会发生这种情况?

解决方案

在 SO 社区的帮助下,我发现了我的问题。我的问题是由于当我创建要附加的实体时,列的默认值设置为零,所以当它试图将值分配为零时...... LinqToSql 说嘿......没有任何改变,所以我没有更新值。

我现在正在做的......只是为了让它发挥作用:

ctx.DataContext.InvoiceItems.Attach(data, true);

这似乎迫使所有值将自己写入数据库。这暂时有效。

【问题讨论】:

  • 在您的类中获得了任何部分方法,例如 OnCreated() 或 OnChanged() 造成干扰?你对你的模型进行了三次直觉检查吗?
  • @Dave Silly 问题......但是你所说的三重肠道检查是什么意思?
  • 我的意思是现在还早,我还没有喝咖啡。 ;-) 我的意思是您是否根据您的数据库仔细检查了您的 dbml 文件的定义(数据类型、可为空、关系)?
  • 明白了! =) 我现在正在这样做......到目前为止一切看起来都很好。我的意思是它确实改变了值,而不是当我试图使其为零时!
  • 你能确认你已经为 SQL 表创建了一个主键,并且 linq 对象知道这个小事实吗? Linq 不会告诉你什么,只是不会更新表格。我希望这会有所帮助。

标签: c# .net linq linq-to-sql


【解决方案1】:

我尝试使用以下代码重现此问题,但对我来说它有效。

using (DataClasses1DataContext ctx = new DataClasses1DataContext())
{
    var obj = ctx.DecimalColumnTables.First();
    Debug.Assert(obj.B != 0);
    obj.B = 0;
    ctx.SubmitChanges();
}

所以我认为您的域中一定有一些特殊的东西导致了这种情况。我建议您使用您的域模型创建一个如此简单的重现,然后看看会发生什么。

LINQ to SQL 忽略对当前值的更新,因此如果该字段已经为零,您可能看不到任何更新。

关闭:您使用的 OR/M 是 LINQ to SQL。 LINQ 是 .NET 中查询功能的名称,但 LINQ 不定义也不实现任何更新逻辑。所以这个问题与 LINQ to SQL 有关,而不是 LINQ。

【讨论】:

  • 你在@Gaspar Nagy 上是对的...... Linq to Sql 忽略了这个变化。
【解决方案2】:

很明显的问题,但您确定该列已映射到 dbml / 映射文件中吗?

另外 - 它是一个计算列吗? (即价格 => 单位 * 单价)

【讨论】:

    【解决方案3】:

    在 SO 社区的帮助下,我发现了我的问题。我的问题是由于当我创建要附加的实体时,列的默认值设置为零,所以当它试图将值分配为零时...... LinqToSql 说嘿......没有任何改变,所以我没有更新值。

    我现在正在做的......只是为了让它发挥作用:

    ctx.DataContext.InvoiceItems.Attach(data, true);
    

    这似乎迫使所有值将自己写入数据库。这暂时有效。

    【讨论】:

      【解决方案4】:

      更多信息……我发现了我的问题……更多的是对 LinqToSql 缺乏了解……我在做什么:

      private void Child_Update(Invoice parent)
      {
            using (var ctx = Csla.Data.ContextManager
                 .GetManager(Database.ApplicationConnection, false))
            {
                 var data = new Gimli.Data.InvoiceItem()
                 {
                      InvoiceItemId = ReadProperty(InvoiceItemIdProperty)
                 };
      
                 ctx.DataContext.InvoiceItems.Attach(data);
      
                 if (this.IsSelfDirty)
                 {
                      // Update properties
                 }
           }
      }
      

      我认为这会加载原始值...发生的情况是它创建了一个具有默认值的新对象...空值,例如小数的 0、唯一标识符的 Guid.Empty 等等。

      因此,当它更新属性时,它会看到 Units 已经为 0,并将其设置为零。好吧,LinqToSql 不会将此视为更改,因此它不会更新该字段。所以我必须做的是:

      ctx.DataContext.InvoiceItems.Attach(data, true);
      

      现在所有的修改都在更新语句中生成,无论是否真的有变化。这行得通……似乎有点骇人听闻!

      【讨论】:

        【解决方案5】:

        正确的答案是使用 Attach 的特殊重载,它接受一个布尔参数将其视为已修改,(错误地使用另一个重载,它根本不起作用):

        ctx.DataContext.InvoiceItems.Attach(data, true);
        

        但请注意,您可能仍需要在“时间戳”类型的表中包含“版本”列。

        【讨论】:

          【解决方案6】:

          我遇到了这个问题,我看到的所有建议都不适用或不起作用。

          但我发现我犯了一个非常简单的错误!

          在更新属性时,我实际上是在调用自定义 Set 方法(因为还有其他一些东西需要更改以响应相关的主要属性)。

          经过几个小时的挠头后,我注意到我的 Set 方法正在更新私有成员而不是公共属性,即 this._Walking = value;

          我所要做的就是将其更改为 this.Walking = value;一切都开始起作用了!

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-05-14
            • 1970-01-01
            • 1970-01-01
            • 2013-05-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多