21

我很难尝试调试 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,但仍然出现相同的错误。

EDIT3: 我已经实现了 Sam 的建议,试图记录生成的 SQL 并捕获 ChangeExceptoinException。这些建议不再阐明,当我的异常被抛出时,我实际上永远不会生成 SQL。

EDIT4: 我在下面找到了一个适合我的答案。它只是一个理论,但它解决了我当前的问题。

4

19 回答 19

32

我总是发现确切知道在 SubmitChanges() 方法中将哪些更改发送到 DataContext 很有用。

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

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

ctx.GetChangeSet();

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

于 2009-04-01T20:59:51.850 回答
8

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

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

在执行此操作时,我注意到了几件事:

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

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

于 2008-09-19T18:27:27.640 回答
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);
      }
    }
  }
于 2008-09-18T10:35:32.503 回答
4

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

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

partial void OnCreated()
{
#if DEBUG
      this.Log = Console.Out;
#endif
}
于 2008-09-18T04:30:34.800 回答
2

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

如果他们抛出一个更具描述性的异常,那就太好了,也许他们会在未来的版本中。(达米安/马特……?)

于 2008-09-18T03:28:46.150 回答
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);
}
于 2012-07-17T19:46:09.693 回答
1

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

这当然只有在你克服异常时才有帮助......

于 2008-09-17T19:29:24.053 回答
1

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

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

于 2008-09-17T22:47:52.550 回答
1

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

JobMaster newJobToCreate = new JobMaster();
newJobToCreate.JobID = 9999
newJobToCreate.ProjectID = "New Project";
this.InsertOnSubmit(newJobToCreate);
this.SubmitChanges();
于 2008-09-18T04:26:08.943 回答
1

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

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

于 2009-08-04T18:01:10.307 回答
0

人力资源管理系统。

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

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

于 2008-09-17T19:49:43.867 回答
0

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

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

于 2008-10-10T17:07:09.953 回答
0

我今天早些时候在这里发布了一个类似的问题:Strange LINQ Exception (Index out of bounds)

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

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

于 2008-10-10T19:38:24.533 回答
0

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

于 2009-02-10T10:15:29.853 回答
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);

其中 context 显然是 DataContext 对象,而“单元”是 Unit 对象的一个​​实例,它是 dbml 文件中的一个数据类。

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

于 2009-03-20T08:42:54.120 回答
0

我有同样的非口语错误。

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

希望这对任何人都有帮助!

于 2009-04-15T08:03:35.527 回答
0

在对 SO# 237415的回答中发布了我对此异常的体验

于 2009-06-05T01:22:57.417 回答
0

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

希望这可以帮助某人。

于 2016-07-22T12:07:26.977 回答
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 运行更新命令时,它还会运行一个 select 语句来接收同一查询中自动生成的值,并期望第一条记录集包含“要求”的列,但在这种情况下,第一行是触发器中的 select 语句中的列。所以 linq-to-sql 期待两个自动生成的列,但它只收到一列(数据错误),这导致了这个异常。

于 2018-11-20T23:13:48.837 回答