Вопрос

Мне действительно трудно пытаться отладить LINQ для 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();

Я поймаю несколько очень странных исключений, когда я запущу это.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

РЕДАКТИРОВАТЬ 2:Я перешел на InsertOnSubmit в соответствии с предложением сиррокко, по-прежнему получая ту же ошибку.

РЕДАКТИРОВАТЬ 3: Я реализовал предложения Сэма, пытаясь зарегистрировать сгенерированный SQL и перехватить ChangeExceptoinException.Эти предложения не проливают больше никакого света, на самом деле я никогда не смогу сгенерировать SQL, когда генерируется мое исключение.

РЕДАКТИРОВАТЬ 4: Ниже я нашел ответ, который подходит мне.Это всего лишь теория, но она исправила мою текущую проблему.

Это было полезно?

Решение 2

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

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

Пока я этим занимался, я заметил пару вещей:

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

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

Другие советы

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

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

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

ctx.GetChangeSet();

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

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

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

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

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

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

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

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

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

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

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

В VS 2008 есть возможность отладки через .NET framework (http://blogs.msdn.com/sburke/archive/2008/01/16/configuring-visual-studio-to-debug-net-framework-source-code.aspx)

Вероятно, это ваш лучший выбор, вы можете видеть, что происходит и каковы все свойства в конкретный момент времени

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

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

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

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

Хрм.

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

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

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

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

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

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

Перекрестный постинг в этом вопросе на случай, если комбинация данных в вопросах поможет доброму самаритянину ответить на любой из них :)

Убедитесь, что все столбцы "первичного ключа" в вашем dbml на самом деле относятся к первичным ключам в таблицах базы данных.У меня только что была ситуация, когда разработчик решил поместить дополнительный столбец PK в dbml, что означало, что 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, класса данных из файла dbml.

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

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

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

Надеюсь, это кому-нибудь поможет!

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

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

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

Это было давно, но у меня была такая же проблема, и ошибка была из-за триггера с оператором 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 ожидал два автоматически сгенерированных столбца, но получил только один столбец (с неверными данными), и это вызвало это исключение.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top