Подтвердить что ты не робот

Отладка LINQ to 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

Есть ли у кого-нибудь инструменты или методы, которые они используют? Я пропустил что-то простое?

ИЗМЕНИТЬ: У меня есть настройка .net-отладки с использованием предложения Slace, однако код .net 3.5 еще не доступен: http://referencesource.microsoft.com/netframework.aspx

EDIT2: Я изменил на InsertOnSubmit в соответствии с предложением sirrocco, все еще получая ту же ошибку.

EDIT3: Я внедрил предложения Сэма, пытающиеся записать созданный SQL и поймать исключение ChangeExceptoinException. Эти предложения не проливают больше света, я никогда не собираюсь генерировать SQL, когда меня бросает исключение.

EDIT4: Я нашел ответ, который работает для меня ниже. Это просто теория, но она исправила мою текущую проблему.

4b9b3361

Ответ 1

Во-первых, спасибо всем за помощь, я наконец нашел ее.

Решение заключалось в том, чтобы удалить файл .dbml из проекта, добавить пустой .dbml файл и повторно заполнить его таблицами, необходимыми для моего проекта, из "Server Explorer".

Я заметил пару вещей, пока я делал это:

  • В системе есть несколько таблиц с двумя словами и пробелом между словами, т.е. "Job Master". Когда я вернул этот стол в файл .dbml, он создаст таблицу с именем "Job_Master", она заменит пространство символом подчеркивания.
  • В исходном файле .dbml один из моих разработчиков прошел через .dbml файл и удалил все подчеркивания, поэтому "Job_Master" станет "JobMaster" в файле .dbml. В коде мы могли бы ссылаться на таблицу в более стандартном соглашении об именах для нас.
  • Моя теория заключается в том, что где-то перевод с "JobMaster" на "Job Master" был потерян при выполнении проекции, и я продолжал сталкиваться с ошибкой массива за пределами границ.

Это только теория. Если кто-то может лучше объяснить это, я хотел бы получить конкретный ответ здесь.

Ответ 2

Мне всегда было полезно узнать, какие изменения отправляются в DataContext в методе SubmitChanges().

Я использую метод DataContext.GetChangeSet(), он возвращает ChangeSet, который содержит 3 объекта только для чтения объектов, которые были добавлены, изменены или удалены.

Вы можете поместить точку останова непосредственно перед вызовом метода SubmitChanges и добавить Watch (или Quick Watch), содержащий:

ctx.GetChangeSet();

Где ctx - текущий экземпляр вашего DataContext, а затем вы сможете отслеживать все изменения, которые будут эффективны при вызове SubmitChanges.

Ответ 3

Мое первое отладочное действие - посмотреть на сгенерированный 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);
      }
    }
  }

Ответ 4

Вы можете создать частичный класс для вашего DataContext и использовать созданный или какой у вас частичный метод для настройки журнала на console.out, завернутый в #if DEBUG.. это поможет вам увидеть запросы, выполняемые во время отладки любой экземпляр используемого datacontext.

Я нашел это полезным при отладке исключений LINQ to SQL.

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

Ответ 5

Ошибка, о которой вы говорите выше, обычно вызвана ассоциациями, указывающими в неправильном направлении. Это происходит очень легко, когда вручную добавляются ассоциации к дизайнеру, поскольку стрелки объединения в дизайнере L2S обращаются назад по сравнению с инструментами моделирования данных.

Было бы неплохо, если бы они бросили более описательное исключение, и, возможно, они будут в будущей версии. (Дэмиен/Мэтт...?)

Ответ 6

Это то, что я сделал

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

Ответ 7

Простое решение может состоять в том, чтобы запустить трассировку в вашей базе данных и проверить, запущены ли против нее запросы - отфильтрованно, чтобы сортировать другие приложения и т.д., обращаясь к базе данных.

Это, конечно, помогает только после того, как вы преодолеете исключения...

Ответ 9

Почему вы делаете UpdateJobMaster в новом экземпляре? Разве это не будет InsertOnSubmit?

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

Ответ 10

Это почти наверняка не будет основной причиной, но я столкнулся с этим одним и тем же исключением в моем проекте и обнаружил, что основная причина заключалась в том, что при построении класса сущности было выбрано исключение. Как ни странно, истинное исключение "потеряно" и вместо этого проявляется как исключение ArgumentOutOfRange, возникающее на итераторе оператора Linq, которое извлекает объект /s.

Если вы получаете эту ошибку, и вы вводили методы OnCreated или OnLoaded в своих POCOs, попробуйте выполнить эти методы.

Ответ 11

Хмм.

Принимая WAG (Wild Ass Guess), мне кажется, что LINQ-SQL пытается найти объект с id, который не существует, так или иначе основан на создании класса JobMaster. Существуют ли внешние ключи, связанные с этой таблицей, так что LINQ to SQL попытается извлечь экземпляр класса, который может не существовать? Кажется, вы устанавливаете ProjectID нового объекта в строку - действительно ли у вас есть идентификатор строки? Если вы пытаетесь установить его в новый проект, вам нужно будет создать новый проект и получить его идентификатор.

Наконец, что делает UpdateJobMaster? Может ли быть что-то такое, что применимо выше?

Ответ 12

Мы фактически прекратили использовать конструктор Linq to SQL для наших крупных проектов, и эта проблема является одной из основных причин. Мы также меняем множество значений по умолчанию для имен, типов данных и отношений, и каждый раз разработчик теряет эти изменения. Я никогда не нашел точной причины, и я не могу достоверно воспроизвести ее.

Это, наряду с другими ограничениями, заставило нас отказаться от дизайнера и разработать классы вручную. После того, как мы привыкли к шаблонам, это на самом деле проще, чем использование дизайнера.

Ответ 13

Сегодня я опубликовал аналогичный вопрос: Странное исключение LINQ (индекс за пределами границ).

Это другой вариант использования - когда эта ошибка возникает во время SubmitChanges(), моя происходит во время простого запроса, но также является ошибкой индекса вне диапазона.

Перекрестная публикация в этом вопросе, если комбинация данных в вопросах помогает хорошему самаритянскому ответу:)

Ответ 14

Убедитесь, что все столбцы "первичного ключа" в вашем dbml действительно связаны с первичными ключами в таблицах базы данных. У меня была ситуация, когда дизайнер решил разместить дополнительный столбец PK в dbml, что означало, что LINQ to SQL не удалось найти обе стороны внешнего ключа при сохранении.

Ответ 15

Недавно я столкнулся с одной и той же проблемой: что я сделал

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, класса Data из файла dbml.

Затем я использовал объект "proce" для установки свойства в экземпляре другого объекта класса данных. Вероятно, механизм LINQ не смог проверить, было ли свойство, которое я устанавливал из объекта "proce", было разрешено в команде INSERT, которую должен был создать LINQ, чтобы добавить в базу данных другой объект класса данных.

Ответ 16

У меня была такая же непонятная ошибка.

У меня было отношение внешнего ключа к столбцу таблицы, который не был основным ключом таблицы, а уникальным столбцом. Когда я изменил уникальный столбец в качестве первичного ключа таблицы, проблема исчезла.

Надеюсь, это поможет любому!

Ответ 17

Отправленный мой опыт с этим исключением в ответе на SO # 237415

Ответ 18

В конце этого вопроса я попытался отладить мой LINQ ChangeConflictException. В конце я понял, что проблема заключалась в том, что я вручную добавил свойство в таблицу в свой DBML файл, но я забыл установить такие свойства, как Nullable (в моем случае это должно было быть правдой) и Тип данных сервера

Надеюсь, это поможет кому-то.