调试LINQ to SQL SubmitChanges()

linq linq-to-sql debugging

27187 观看

19回复

我很难尝试调试LINQ to SQL并提交更改。

我一直在使用http://weblogs.asp.net/scottgu/archive/2007/07/31/linq-to-sql-debug-visualizer.aspx,它非常适合调试简单查询。

我在我的项目的DataContext类中使用我的应用程序中的以下代码段:

JobMaster newJobToCreate = new JobMaster();
newJobToCreate.JobID = 9999
newJobToCreate.ProjectID = "New Project";
this.UpdateJobMaster(newJobToCreate);
this.SubmitChanges();

当我运行this.SubmitChanges时,我会发现一些非常奇怪的例外;

Index was outside the bounds of the array.

堆栈跟踪进入我无法进入的位置:

at System.Data.Linq.IdentityManager.StandardIdentityManager.MultiKeyManager`3.TryCreateKeyFromValues(Object[] values, MultiKey`2& k)
   at System.Data.Linq.IdentityManager.StandardIdentityManager.IdentityCache`2.Find(Object[] keyValues)
   at System.Data.Linq.IdentityManager.StandardIdentityManager.Find(MetaType type, Object[] keyValues)
   at System.Data.Linq.CommonDataServices.GetCachedObject(MetaType type, Object[] keyValues)
   at System.Data.Linq.ChangeProcessor.GetOtherItem(MetaAssociation assoc, Object instance)
   at System.Data.Linq.ChangeProcessor.BuildEdgeMaps()
   at System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode)
   at System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)
   at System.Data.Linq.DataContext.SubmitChanges()
   at JobTrakDataContext.CreateNewJob(NewJob job, String userName) in D:\JobTrakDataContext.cs:line 1119

有没有人有他们使用的任何工具或技术?我错过了一些简单的事吗?

编辑:我使用Slace的建议设置.net调试,但.net 3.5代码尚不可用:http://referencesource.microsoft.com/netframework.aspx

EDIT2:根据sirrocco的建议,我已经改为InsertOnSubmit,仍然会出现同样的错误。

编辑3: 我已经实现了Sam的建议,试图记录生成的SQL并捕获ChangeExceptoinException。这些建议没有任何消息,当我抛出异常时,我实际上从未实际生成SQL。

编辑4: 我找到了一个对我有用的答案。它只是一个理论,但它已经解决了我目前的问题。

作者: ben 的来源 发布者: 2019 年 6 月 6 日

回应 (19)


30

我总是觉得有用的是确切地知道在SubmitChanges()方法中发送到DataContext的更改。

我使用DataContext.GetChangeSet()方法,它返回一个ChangeSet对象实例,该实例包含已添加,修改或删除的3个只读IList对象。

您可以在SubmitChanges方法调用之前放置一个断点,并添加一个Watch(或Quick Watch),其中包含:

ctx.GetChangeSet();

其中ctx是DataContext的当前实例,然后您将能够跟踪在SubmitChanges调用中有效的所有更改。

作者: CMS 发布者: 01.04.2009 08:59

8

决定

首先,感谢大家的帮助,我终于找到了它。

解决方案是从项目中删除.dbml文件,添加一个空白.dbml文件,并使用“服务器资源管理器”中的项目所需的表重新填充它。

我在做这件事时注意到了几件事:

  • 系统中有几个表以两个单词命名,单词之间有一个空格,即“Job Master”。当我将该表拉回到.dbml文件中时,它将创建一个名为“Job_Master”的表,它将用下划线替换该空格。
  • 在原始.dbml文件中,我的一个开发人员已经浏览了.dbml文件并删除了所有下划线,因此'job_Master'将成为.dbml文件中的'JobMaster'。在代码中,我们可以在更多的标准命名约定中引用该表。
  • 我的理论是在某个地方,从“JobMaster”到“Job Master”的转换虽然在进行投影时丢失了,但我仍然不断提出数组越界错误。

这只是一种理论。如果有人能够更好地解释它,我希望在这里有一个具体的答案。

作者: ben 发布者: 19.09.2008 06:27

6

我的第一个调试操作是查看生成的SQL:

JobMaster newJobToCreate = new JobMaster();
newJobToCreate.JobID = 9999
newJobToCreate.ProjectID = "New Project";
this.UpdateJobMaster(newJobToCreate);
this.Log = Console.Out; // prints the SQL to the debug console
this.SubmitChanges();

第二个是捕获ChangeConflictException并查看失败的详细信息。

  catch (ChangeConflictException e)
  {
    Console.WriteLine("Optimistic concurrency error.");
    Console.WriteLine(e.Message);
    Console.ReadLine();
    foreach (ObjectChangeConflict occ in db.ChangeConflicts)
    {
      MetaTable metatable = db.Mapping.GetTable(occ.Object.GetType());
      Customer entityInConflict = (Customer)occ.Object;
      Console.WriteLine("Table name: {0}", metatable.TableName);
      Console.Write("Customer ID: ");
      Console.WriteLine(entityInConflict.CustomerID);
      foreach (MemberChangeConflict mcc in occ.MemberConflicts)
      {
        object currVal = mcc.CurrentValue;
        object origVal = mcc.OriginalValue;
        object databaseVal = mcc.DatabaseValue;
        MemberInfo mi = mcc.Member;
        Console.WriteLine("Member: {0}", mi.Name);
        Console.WriteLine("current value: {0}", currVal);
        Console.WriteLine("original value: {0}", origVal);
        Console.WriteLine("database value: {0}", databaseVal);
      }
    }
  }
作者: Sam 发布者: 18.09.2008 10:35

4

您可以为DataContext创建一个分部类,并使用Created或者您有部分方法将日志设置为包含在#if DEBUG中的console.out ..这将帮助您查看在调试任何实例时执行的查询您正在使用的datacontext。

调试LINQ to SQL异常时,我发现这很有用。

partial void OnCreated()
{
#if DEBUG
      this.Log = Console.Out;
#endif
}
作者: Quintin Robinson 发布者: 18.09.2008 04:30

2

您在上面提到的错误通常是由指向错误方向的关联引起的。当手动向设计器添加关联时,这很容易发生,因为与数据建模工具相比,L2S设计器中的关联箭头指向后方。

如果他们抛出更具描述性的异常会很好,也许他们会在将来的版本中。(Damien / Matt ......?)

作者: KristoferA 发布者: 18.09.2008 03:28

2

这就是我做的

...
var builder = new StringBuilder();
try
{
    context.Log = new StringWriter(builder);
    context.MY_TABLE.InsertAllOnSubmit(someData);
    context.SubmitChanges();                
}
finally
{
    Log.InfoFormat("Some meaningful message here... ={0}", builder);
}
作者: OscarRyz 发布者: 17.07.2012 07:46

1

一个简单的解决方案可能是在您的数据库上运行跟踪并检查针对它运行的查询 - 过滤用于理清访问数据库的其他应用程序等。

一旦你超越了例外,那只会有帮助...

作者: Per Hornshøj-Schierbeck 发布者: 17.09.2008 07:29

1

VS 2008具有通过.NET框架进行调试的能力(http://blogs.msdn.com/sburke/archive/2008/01/16/configuring-visual-studio-to-debug-net-framework-source-code .aspx

这可能是您最好的选择,您可以在确切的时间点看到正在发生的事情以及所有属性

作者: Aaron Powell 发布者: 17.09.2008 10:47

1

为什么要在新实例上执行UpdateJobMaster?不应该是InsertOnSubmit吗?

JobMaster newJobToCreate = new JobMaster();
newJobToCreate.JobID = 9999
newJobToCreate.ProjectID = "New Project";
this.InsertOnSubmit(newJobToCreate);
this.SubmitChanges();
作者: sirrocco 发布者: 18.09.2008 04:26

1

这几乎肯定不是每个人的根本原​​因,但我在我的项目中遇到了这个完全相同的异常 - 并且发现根本原因是在构造实体类期间抛出异常。奇怪的是,真正的异常是“丢失”,而是表现为一个ArgumentOutOfRange异常,它起源于检索对象的Linq语句的迭代器。

如果您收到此错误并且已在POCO上引入了OnCreated或OnLoaded方法,请尝试单步执行这些方法。

作者: Mark 发布者: 04.08.2009 06:01

0

人力资源管理。

采用WAG(Wild Ass Guess),它看起来像LINQ - SQL试图找到一个id不存在的对象,基于JobMaster类的创建。是否存在与该表相关的外键,以便LINQ to SQL将尝试获取可能不存在的类的实例?您似乎将新对象的ProjectID设置为字符串 - 您真的有一个字符串的id吗?如果您尝试将其设置为新项目,则需要创建一个新项目并获取其ID。

最后,UpdateJobMaster做了什么?它可以做一些上述适用的事情吗?

作者: John Christensen 发布者: 17.09.2008 07:49

0

我们实际上已经停止使用Linq to SQL设计器来处理大型项目,这个问题是主要原因之一。我们还更改了名称,数据类型和关系的许多默认值,设计师每隔一段时间就会丢失这些更改。我从来没有找到确切的原因,我无法可靠地重现它。

这与其他限制一起导致我们放弃设计师并手工设计课程。在我们习惯了模式之后,它实际上比使用设计器更容易。

作者: amcoder 发布者: 10.10.2008 05:07

0

我今天早些时候在这里发布了一个类似的问题:奇怪的LINQ异常(索引超出范围)

这是一个不同的用例 - 在SubmitChanges()期间发生此错误,我在简单查询期间发生,但它也是索引超出范围错误。

在这个问题中交叉发布,以防问题中的数据组合有助于一个好的撒玛利亚人回答:)

作者: Matt 发布者: 10.10.2008 07:38

0

检查dbml中的所有“主键”列是否与数据库表上的主键实际相关。我只是遇到设计师决定在dbml中添加额外PK列的情况,这意味着LINQ to SQL在保存时无法找到外键的两面。

作者: Neil Barnwell 发布者: 10.02.2009 10:15

0

我最近遇到了同样的问题:我做的是

Proce proces = unit.Proces.Single(u => u.ProcesTypeId == (from pt in context.ProcesTypes
                                                                         where pt.Name == "Fix-O"
                                                                         select pt).Single().ProcesTypeId &&
                                                                      u.UnitId == UnitId);

代替:

Proce proces = context.Proces.Single(u => u.ProcesTypeId == (from pt in context.ProcesTypes
                                                                     where pt.Name == "Fix-O"
                                                                     select pt).Single().ProcesTypeId &&
                                                                  u.UnitId == UnitId);

上下文显然是DataContext对象,“unit”是Unit对象的实例,dbcl文件中的数据类。

接下来,我使用“proce”对象在另一个Data Class对象的实例中设置属性。可能LINQ引擎无法检查我在“proc”对象中设置的属性是否允许在INSERT命令中,该命令必须由LINQ创建,以将其他Data Class对象添加到数据库中。

作者: craziac 发布者: 20.03.2009 08:42

0

我有同样的非说话错误。

我有一个表的列的外键关系,它不是表的主键,而是一个唯一的列。当我将唯一列更改为表的主键时,问题就消失了。

希望这有助于任何人!

作者: Sebastian 发布者: 15.04.2009 08:03

0

在SO#237415的答案中发表了我对这个例外的经历

作者: Jim Counts 发布者: 05.06.2009 01:22

0

在尝试调试LINQ ChangeConflictException时,我最终得到了这个问题。最后我意识到问题是我手动将属性添加到我的DBML文件中的表中,但是我忘了设置像Nullable这样的属性(在我的情况下应该是真的)和服务器数据类型

希望这有助于某人。

作者: RuudvK 发布者: 22.07.2016 12:07

0

这是很久以前的事了,但是我遇到了同样的问题而且错误是因为带有select语句的触发器。就像是

CREATE TRIGGER NAME ON TABLE1 AFTER UPDATE AS SELECT table1.key from table1 
inner join inserted on table1.key = inserted.key

当linq-to-sql运行update命令时,它还运行一个select语句来接收同一查询中自动生成的值,并期望第一个记录集包含“要求”的列,但在这种情况下,第一行是来自触发器中select语句的列。所以linq-to-sql期待两个自动生成的列,但它只收到一列(有错误的数据),这导致了这个异常。

作者: Mr Zach 发布者: 20.11.2018 11:13
32x32