Здравствуйте. Не могу понять, в чем дело.
Есть две базы, одна обновляется данными из другой.
Процесс обновления происходит следующим образом. Вызывается GetRooms(), выбираются данные из второй базы, производится шаманство и результирующий список попадает на вход функции ReplaceOldValues.
public static List<Room> GetRooms()
{
return (from r in LinqUtil.Db.Rooms select r).ToList<Room>();
}
public static void ReplaceOldValues(List<Room> rooms)
{
LinqUtil.Db.Rooms.DeleteAllOnSubmit(GetRooms());
DAL.LinqUtil.SubmitChanges();
//var test = GetRooms();
LinqUtil.Db.Rooms.InsertAllOnSubmit(rooms);
DAL.LinqUtil.SubmitChanges();
}
Данный подход (в данной реализации) работает исключительно с пустой БД. Если заполняемая база не пуста, то выделеная строчка кидает эксепшн: Cannot add an entity that already exists. Что странно, в режиме отладки, закомментированая переменная test имеет count = 0 (т.е. не содержит записей).
В итоге я получаю, что алгоритм работает через раз. Данных нет — данные появляются — Данных нет (в результате эксепшена) — данные появляются — ..
Подскажите пожалуйста, что я делаю не так.
P.S. Критика алгоритма также приветствуется.
дайте слепому показать вам дорогу.
(Р. Бредбери "Смерть — дело одинокое")
Здравствуйте, ascii32, Вы писали:
A>Данный подход (в данной реализации) работает исключительно с пустой БД. Если заполняемая база не пуста, то выделеная строчка кидает эксепшн: Cannot add an entity that already exists. Что странно, в режиме отладки, закомментированая переменная test имеет count = 0 (т.е. не содержит записей).
А если после DeleteAllOnSubmit вызвать SubmitChanges?
... << RSDN@Home 1.2.0 alpha rev. 786>>
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, ascii32, Вы писали:
L>А если после DeleteAllOnSubmit вызвать SubmitChanges?
А я вызываю.
LinqUtil.Db.Rooms.DeleteAllOnSubmit(GetRooms());
DAL.LinqUtil.SubmitChanges();
Правда для ясности надо было DAL (пространство имен) убрать (делал пример ошибки в спешке).
Вообще, удалось забороть проблему, но она от этого непонятней не стала. Исходный код работает как ожидалось, если после первого SubmitChanges (после удаления) освободить DataContext и создать заново

.
дайте слепому показать вам дорогу.
(Р. Бредбери "Смерть — дело одинокое")
Здравствуйте, ascii32, Вы писали:
Похоже что кроме пересоздания контекста ничего сделать нельзя
На мой поверхностный взгляд тут какие-то косяки в реализации трекинга объектов в LINQ to SQL.
Вариант 1. Ты добавляешь объект, который ты достал из базы. Твое исключение вылетает на следующем коде в InsertOnSubmit:
if (trackedObject == null)
{
this.context.Services.ChangeTracker.Track(entity).ConvertToNew();
}
else if (trackedObject.IsWeaklyTracked)
{
trackedObject.ConvertToNew();
}
else if (trackedObject.IsDeleted)
{
trackedObject.ConvertToPossiblyModified();
}
else if (trackedObject.IsRemoved)
{
trackedObject.ConvertToNew();
}
else if (!trackedObject.IsNew)
{
throw Error.CantAddAlreadyExistingItem(); // вот тут вылетает исключение. Хотя если подумать, то правильнее было бы если бы сработал if с IsDeleted
}
Вариант 2. Я попробовал создать новый объект вместо reusing старого (но с существовавшим ранее ключем). Всё равно вылетает исключение но уже на сабмите в
ChangeProcessor.TrackUntrackedObjects(MetaType type, object item, Dictionary<object, object> visited)
...
object obj3 = this.services.InsertLookupCachedObject(trackedObject.Type, item);
if (obj3 != item)
{
TrackedObject obj4 = this.tracker.GetTrackedObject(obj3);
if (!obj4.IsDeleted && !obj4.CanInferDelete())
{
if (!obj4.IsDead)
{
throw new DuplicateKeyException(item, Strings.CantAddAlreadyExistingKey); // вот тут исключение наше
}
}
Как видно LINQtoSQL испытывает тут те же проблемы с определением что obj4 (т.е. старый Room с таким же ключем был успешно удален)
Короче спасибо за вопрос, будем иметь ввиду такие тонкости

... << RSDN@Home 1 alpha 4 rev. 0>>
Здравствуйте, Mace Windu, Вы писали:
Итого: если через контекст был удален объект, добавлять объект с тем же ключем придется через новый контекст. Ничего в принципе страшного в этом нет.
... << RSDN@Home 1 alpha 4 rev. 0>>