将LINQ调试为SQL SubmitChanges()
我很难调试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
编辑2:
根据sirrocco的建议,我已更改为InsertOnSubmit,但仍然出现相同的错误。
编辑3:
我已经实施了Sam的建议,试图记录生成的SQL并捕获ChangeExceptoinException。这些建议不再引起人们的注意,抛出异常时,我实际上从未生成过SQL。
编辑4:
我在下面找到了一个对我有用的答案。它只是一个理论,但它已经解决了我当前的问题。
解决方案
回答
一个简单的解决方案是在数据库上运行跟踪,并根据过滤后的结果检查运行查询,以整理出其他应用程序等访问数据库。
当然,这只有在我们克服了例外之后才有所帮助。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
回答
嗯
以WAG(Wild Ass Guess)为例,在我看来LINQ SQL试图基于JobMaster类的创建来查找ID不存在的对象。是否有与该表相关的外键,以便LINQ to SQL会尝试获取一个类的实例(该类可能不存在)?我们似乎正在将新对象的ProjectID设置为字符串,我们是否真的有一个ID是字符串?如果我们尝试将其设置为新项目,则需要创建一个新项目并获取其ID。
最后,UpdateJobMaster是做什么的?可以做一些上述事情适用的事情吗?
回答
VS 2008可以通过.NET框架进行调试(http://blogs.msdn.com/sburke/archive/2008/01/16/configuring-visual-studio-to-debug-net-framework-source-code .aspx)
这可能是最好的选择,我们可以看到正在发生的事情以及确切时间点的所有属性
回答
我们上面提到的错误通常是由指向错误方向的关联引起的。手动将关联添加到设计器中时,这很容易发生,因为与数据建模工具相比,L2S设计器中的关联箭头指向后方。
如果他们抛出一个更具描述性的例外,那就太好了,也许他们会在将来的版本中发布。 (达米恩/马特...?)
回答
为什么要在新实例上执行UpdateJobMaster?它不应该是InsertOnSubmit吗?
JobMaster newJobToCreate = new JobMaster(); newJobToCreate.JobID = 9999 newJobToCreate.ProjectID = "New Project"; this.InsertOnSubmit(newJobToCreate); this.SubmitChanges();
回答
我们可以为DataContext创建一个部分类,并使用Created或者我们使用的部分方法来将日志设置到console.out中,并包装在#if DEBUG中。这将查看在调试任何实例时执行的查询我们正在使用的datacontext。
我发现这在调试LINQ to SQL异常时非常有用。
partial void OnCreated() { #if DEBUG this.Log = Console.Out; #endif }
回答
我的第一个调试操作是查看生成的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); } } }
回答
首先,感谢大家的帮助,我终于找到了它。
解决方案是从项目中删除.dbml文件,添加一个空白的.dbml文件,然后使用"服务器浏览器"中我项目所需的表重新填充该文件。
在执行此操作时,我注意到了几件事:
- 系统中有几个表,两个表用两个单词命名,单词之间有一个空格,即" Job Master"。当我将该表拉回到.dbml文件时,它将创建一个名为" Job_Master"的表,它将用下划线替换该空间。
- 在原始的.dbml文件中,我的一位开发人员浏览了.dbml文件并删除了所有下划线,因此'Job_Master'在.dbml文件中将变为'JobMaster'。然后,在代码中,我们可以使用更多的标准命名约定来引用表。
- 我的理论是,在某处,从" JobMaster"到" Job Master"的翻译在进行投影时丢失了,我一直想出数组超出范围的错误。
这只是一个理论。如果有人可以更好地解释它,我希望在这里有一个具体的答案。
回答
实际上,我们已经停止对大型项目使用Linq to SQL设计器,而这个问题是主要原因之一。我们还更改了许多名称,数据类型和关系的默认值,设计人员有时会丢失这些更改。我从来没有找到确切的原因,也无法可靠地重现它。
那,加上其他限制,导致我们放弃了设计师并手工设计课程。在习惯了模式之后,实际上比使用设计器要容易。
回答
我今天早些时候在这里发布了一个类似的问题:奇怪的LINQ异常(索引超出范围)。
这是一个不同的用例,其中此错误发生在SubmitChanges()期间,我的错误发生在简单查询中,但这也是索引超出范围错误。
如果问题中的数据组合有助于撒马利亚人很好地回答,则在此问题中交叉发布:)
回答
检查dbml中的所有"主键"列是否确实与数据库表上的主键相关。我只是遇到一种情况,设计人员决定在dbml中放置一个额外的PK列,这意味着LINQ to SQL在保存时找不到外键的两面。
回答
我最近遇到了同样的问题:我所做的是
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对象的实例,Unit对象是dbml文件中的数据类。
接下来,我使用" proce"对象在另一个"数据类"对象的实例中设置属性。 LINQ引擎可能无法检查INSQ命令是否允许我在" proce"对象中设置的属性,而INSERT命令将由LINQ创建,以将另一个"数据类"对象添加到数据库中。
回答
我总是发现准确地知道在SubmitChanges()方法中将什么更改发送到DataContext很有用。
我使用DataContext.GetChangeSet()方法,它返回一个ChangeSet对象实例,该实例包含3个只读的IList对象,这些对象已被添加,修改或者移除。
我们可以在SubmitChanges方法调用之前放置一个断点,并添加一个包含以下内容的Watch(或者Quick Watch):
ctx.GetChangeSet();
其中ctx是DataContext的当前实例,然后我们将能够跟踪所有对SubmitChanges调用生效的更改。
回答
我有同样的非说话错误。
我与表的列有外键关系,该表不是表的主键,而是唯一的列。
当我将唯一列更改为表的主键时,问题就消失了。
希望这对任何人有帮助!
回答
在对SO237415的答复中发表了我的例外情况经验
回答
这几乎肯定不是所有人的根本原因,但是我在项目中遇到了这个完全相同的异常,并且发现根本原因是在构造实体类时抛出了异常。奇怪的是,真正的异常是"丢失"的,而是表现为ArgumentOutOfRange异常,该异常起源于检索对象的Linq语句的迭代器。
如果收到此错误,并且在POCO上引入了OnCreated或者OnLoaded方法,请尝试逐步执行这些方法。