web-dev-qa-db-ja.com

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

誰かが使用するツールやテクニックを持っていますか?簡単なものが足りませんか?

[〜#〜] edit [〜#〜]:Slaceの提案を使用して.netデバッグをセットアップしましたが、.net3.5コードはまだありません利用可能: http://referencesource.Microsoft.com/netframework.aspx

EDIT2:sirroccoの提案に従ってInsertOnSubmitに変更しましたが、それでも同じエラーが発生します。

EDIT3:生成されたSQLをログに記録し、ChangeExceptoinExceptionをキャッチしようとするSamの提案を実装しました。これらの提案はこれ以上光を当てることはありません。例外がスローされているときに実際にSQLを生成することはできません。

EDIT4:私は以下で私のために働く答えを見つけました。それは単なる理論ですが、それは私の現在の問題を修正しました。

21
ben

まず、みんなの助けに感謝し、ついに見つけました。

解決策は、プロジェクトから.dbmlファイルを削除し、空の.dbmlファイルを追加して、「サーバーエクスプローラー」からプロジェクトに必要なテーブルを再入力することでした。

これを行っているときに、いくつかのことに気づきました。

  • システムには、2つの単語と単語の間にスペースを入れて名前が付けられたテーブルがいくつかあります。つまり、「ジョブマスター」です。そのテーブルを.dbmlファイルにプルバックすると、「Job_Master」というテーブルが作成され、スペースがアンダースコアに置き換えられます。
  • 元の.dbmlファイルでは、開発者の1人が.dbmlファイルを調べてすべての下線を削除したため、「Job_Master」は.dbmlファイルでは「JobMaster」になります。コードでは、標準の命名規則でテーブルを参照できます。
  • 私の理論では、どこかで、投影の実行中に「JobMaster」から「Job Master」への変換が失われ、配列の範囲外エラーが発生し続けました。

それはただの理論です。誰かがそれをよりよく説明できるなら、私はここで具体的な答えが欲しいです。

8
ben

SubmitChanges()メソッドでDataContextに送信されている変更を正確に知ることは常に役に立ちます。

DataContext.GetChangeSet() メソッドを使用すると、追加、変更、または削除されたオブジェクトの3つの読み取り専用IListを保持する ChangeSet オブジェクトインスタンスが返されます。

SubmitChangesメソッド呼び出しの直前にブレークポイントを設定し、以下を含むウォッチ(またはクイックウォッチ)を追加できます。

ctx.GetChangeSet();

ここで、ctxはDataContextの現在のインスタンスであり、SubmitChanges呼び出しで有効になるすべての変更を追跡できます。

31
CMS

私の最初のデバッグアクションは、生成された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();

2つ目は、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);
      }
    }
  }
6
Sam

DataContextの部分クラスを作成し、Createdメソッドまたはwhat have partメソッドを使用して、#if DEBUGでラップされたconsole.outへのログを設定できます。これにより、のインスタンスのデバッグ中に実行されたクエリを確認できます。使用しているデータコンテキスト。

LINQ to SQL例外をデバッグするときに、これが役立つことがわかりました。

partial void OnCreated()
{
#if DEBUG
      this.Log = Console.Out;
#endif
}
4

これは私がしたことです

...
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);
}
2
OscarRyz

上記で参照しているエラーは通常、関連付けが間違った方向を指しているが原因で発生します。 L2Sデザイナのアソシエーション矢印は、データモデリングツールと比較すると後方を向いているため、これは、アソシエーションをデザイナに手動で追加するときに非常に簡単に発生します。

彼らがもっと説明的な例外を投げたらいいのにと思います、そして多分彼らは将来のバージョンでそうするでしょう。 (ダミアン/マット...?)

2
KristoferA

VS 2008には、.NET Frameworkを介してデバッグする機能があります( http://blogs.msdn.com/sburke/archive/2008/01/16/configuring-visual-studio-to-debug-net-framework -source-code.aspx

これはおそらくあなたの最善の策です、あなたは何が起こっているのか、そしてすべてのプロパティが正確な時点で何であるかを見ることができます

1
Aaron Powell

新しいインスタンスでUpdateJobMasterを実行するのはなぜですか? InsertOnSubmitではありませんか?

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

簡単な解決策は、データベースでトレースを実行し、それに対して実行されたクエリを検査することです。もちろん、データベースにアクセスする他のアプリケーションなどを分類するためにフィルタリングされます。

もちろん、その例外を乗り越えた場合にのみ役立ちます...

これがすべての人の根本的な原因になることはほぼ間違いありませんが、プロジェクトでまったく同じ例外が発生しました。根本的な原因は、エンティティクラスの構築中に例外がスローされたことであることがわかりました。奇妙なことに、真の例外は「失われた」ものであり、代わりに、オブジェクトを取得するLinqステートメントのイテレーターで発生するArgumentOutOfRange例外として現れます。

このエラーが発生し、POCOにOnCreatedまたはOnLoadedメソッドを導入した場合は、それらのメソッドをステップ実行してみてください。

1
Mark

今日、同様の質問をここに投稿しました: 奇妙なLINQ例外(範囲外のインデックス)

これは別のユースケースです。このバグはSubmitChanges()中に発生し、私のものは単純なクエリ中に発生しますが、インデックスが範囲外のエラーでもあります。

質問のデータの組み合わせがサマリア人の良い答えに役立つ場合は、この質問のクロスポスト:)

0
Matt

私は最近同じ問題に遭遇しました:私がしたことは

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オブジェクトのインスタンスである場合、dbmlファイルのデータクラスです。

次に、「proce」オブジェクトを使用して、別のデータクラスオブジェクトのインスタンスにプロパティを設定しました。おそらく、LINQエンジンは、「proce」オブジェクトから設定したプロパティが、他のデータクラスオブジェクトをデータベースに追加するためにLINQによって作成される必要があるINSERTコマンドで許可されているかどうかを確認できませんでした。

0
craziac

SO#への回答でこの例外に関する私の経験を投稿しました 237415

0
Jim Counts

大規模なプロジェクトでLinqto SQLデザイナーの使用を実際に停止しましたが、この問題が主な理由の1つです。また、名前、データ型、および関係の多くのデフォルト値を変更し、設計者がそれらの変更を失うことがあります。正確な理由はわかりませんでしたし、確実に再現することもできません。

それは、他の制限とともに、デザイナーを落としてクラスを手作業で設計することを引き起こしました。パターンに慣れたら、デザイナーを使うよりも実際は簡単です。

0
amcoder

Dbmlのすべての「主キー」列が実際にデータベーステーブルの主キーに関連していることを確認してください。設計者がdbmlに追加のPK列を配置することを決定したという状況がありました。これは、保存時にLINQ toSQLが外部キーの両側を見つけることができなかったことを意味します。

0
Neil Barnwell

LINQ ChangeConflictExceptionをデバッグしようとしたときに、この質問に行き着きました。結局、問題はDBMLファイルのテーブルにプロパティを手動で追加したことであることに気付きましたが、Nullable(私の場合はtrueであるはずです)や-のようなプロパティを設定するのを忘れました。 サーバーデータ型

これが誰かを助けることを願っています。

0
RuudvK

私は同じ非発話エラーを持っていました。

テーブルの主キーではなく、一意の列であるテーブルの列に外部キー関係がありました。一意の列をテーブルの主キーに変更すると、問題は解決しました。

これが誰かに役立つことを願っています!

0
Sebastian

うーん。

WAG(Wild Ass Guess)を使用すると、LINQのように見えます-SQLは、JobMasterクラスの作成に基づいて、存在しないIDを持つオブジェクトを見つけようとしています。 LINQ to SQLが存在しない可能性のあるクラスのインスタンスをフェッチしようとするような、そのテーブルに関連する外部キーはありますか?新しいオブジェクトのProjectIDを文字列に設定しているようです-本当に文字列であるIDを持っていますか?新しいプロジェクトに設定しようとしている場合は、新しいプロジェクトを作成してそのIDを取得する必要があります。

最後に、UpdateJobMasterは何をしますか?上記が当てはまるようなことをしているのでしょうか?

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は2つの自動生成された列を予期していましたが、1つの列(間違ったデータ)しか受信しなかったため、この例外が発生していました。

0
Mr Zach