Отладка 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:
Я нашел ответ, который работает для меня ниже. Это просто теория, но она исправила мою текущую проблему.
Ответы
Ответ 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
Простое решение может состоять в том, чтобы запустить трассировку в вашей базе данных и проверить, запущены ли против нее запросы - отфильтрованно, чтобы сортировать другие приложения и т.д., обращаясь к базе данных.
Это, конечно, помогает только после того, как вы преодолеете исключения...
Ответ 8
VS 2008 имеет возможность отлаживать платформу .NET(http://blogs.msdn.com/sburke/archive/2008/01/16/configuring-visual-studio-to-debug-net-framework-source-code.aspx)
Это, вероятно, лучший выбор, вы можете увидеть, что происходит и что все свойства находятся в точный момент времени.
Ответ 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 (в моем случае это должно было быть правдой) и Тип данных сервера
Надеюсь, это поможет кому-то.