Я пытаюсь написать программу, которая использует Linq-to-SQL для взаимодействия с базой данных (MS SQL Server 2008). Добавление и удаление, кажется, в порядке, но я не могу вспомнить обновления.
У сущности есть столбец версии, который является столбцом метки времени в базе данных и используется для оптимистической блокировки, встроенной в Linq-to-SQL. Я установил для свойства «Проверка обновлений» для всех полей объекта значение «Никогда».
У меня есть следующий SaveTaskCommand, который используется для вставки и обновления сущностей, в зависимости от того, была ли конкретная задача уже добавлена в базу данных.
public class SaveTaskCommand : CustomCommand
{
private Task _task;
private TaskDetailsViewModel _taskDetails;
public SaveTaskCommand(Task task, TaskDetailsViewModel taskDetails)
{
_task = task;
_taskDetails = taskDetails;
}
public override void Execute(object parameter)
{
TaskRepository taskRepository = new TaskRepository();
if (!taskRepository.ContainsTask(_task))
{
taskRepository.AddTask(_task);
_taskDetails.Mediator.NotifyColleagues(ViewModelMessages.TaskAdded,
_task);
}
else
{
taskRepository.UpdateTask(_task);
_taskDetails.Mediator.NotifyColleagues(
ViewModelMessages.TaskAmended, null);
}
}
public override bool CanExecute(object parameter)
{
return _task.IsValid();
}
}
Класс CustomCommand - это просто класс, заключающий в себе ICommand и работающий с событием CanExecuteChanged, так что мне не пришлось повторять код в каждой из команд.
Как вы можете видеть, TaskRepository создается в методе Execute () команды, которая сначала проверяет, есть ли задача в базе данных, а затем выбирает, вставлять или обновлять. Код для TaskRepository приведен ниже.
public class TaskRepository : IRepository
{
private DataContextDataContext _dataContext;
public TaskRepository()
{
_dataContext = new DataContextDataContext();
}
public List<Task> GetAllTasks()
{
return _dataContext.Tasks.ToList();
}
public Task GetForKeyTable(int keyTable)
{
return _dataContext.Tasks.Where(t => t.KeyTable == keyTable).
FirstOrDefault();
}
public void AddTask(Task task)
{
task.Project = _dataContext.Projects.SingleOrDefault(
p => p.KeyTable == task.KeyProject);
_dataContext.Tasks.InsertOnSubmit(task);
_dataContext.SubmitChanges();
}
public void UpdateTask(Task task)
{
//exception occurs here
_dataContext.Tasks.Attach(task, GetForKeyTable(task.KeyTable));
_dataContext.SubmitChanges();
}
public void DeleteTask(Task task)
{
_dataContext.Tasks.Attach(task, GetForKeyTable(task.KeyTable));
_dataContext.Tasks.DeleteOnSubmit(task);
_dataContext.SubmitChanges();
}
public bool ContainsTask(Task task)
{
return GetForKeyTable(task.KeyTable) != null;
}
}
В указанной строке я получаю следующее исключение:
Была предпринята попытка присоединить или
Возможно, добавьте объект, который не является новым
будучи загруженным из другого
DataContext. Это не поддерживается.
Я не понимаю, почему я получаю это исключение, когда передаю исходную версию сущности. Я получаю то же исключение, если меняю закомментированную строку на
_dataContext.Tasks.Attach(task, true);
Любая помощь будет принята с благодарностью.
Обновление
Я сделал свой репозиторий реализующим IDisposable и менял везде, где вызывается конструктор, использующий using (TaskRepository taskRepository = new TaskRepository)
. В Dispose()
методе TaskRepository
я вызвал Dispose()
в моем контексте данных.
Я также изменил метод Update()
для вызова Detach()
для моего объекта Task. Мой код теперь выглядит так:
public class TaskRepository : IRepository, IDisposable
{
private DataContextDataContext _dataContext;
public TaskRepository()
{
_dataContext = new DataContextDataContext();
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Task>(t => t.Project);
dlo.LoadWith<Task>(t => t.Priority);
_dataContext.LoadOptions = dlo;
}
public List<Task> GetAllTasks()
{
return _dataContext.Tasks.ToList();
}
public Task GetForKeyTable(int keyTable)
{
return _dataContext.Tasks.Where(t => t.KeyTable == keyTable).FirstOrDefault();
}
public void AddTask(Task task)
{
task.Project = _dataContext.Projects.SingleOrDefault(p => p.KeyTable == task.KeyProject);
_dataContext.Tasks.InsertOnSubmit(task);
_dataContext.SubmitChanges();
}
public void UpdateTask(Task task)
{
task.Detach();
_dataContext.Tasks.Attach(task, true); //exception occurs here
_dataContext.Refresh(RefreshMode.KeepCurrentValues, task);
_dataContext.SubmitChanges();
}
public void DeleteTask(Task task)
{
_dataContext.Tasks.Attach(task, GetForKeyTable(task.KeyTable));
_dataContext.Tasks.DeleteOnSubmit(task);
_dataContext.SubmitChanges();
}
public bool ContainsTask(Task task)
{
return GetForKeyTable(task.KeyTable) != null;
}
#region IDisposable Members
public void Dispose()
{
_dataContext.Dispose();
}
#endregion
}
Метод Detach () в Задаче таков:
public void Detach()
{
this._Project = default(EntityRef<Project>);
this._Priority = default(EntityRef<Priority>);
}
Для справки, мои сущности выглядят так:
![Database layout](https://i.stack.imgur.com/J31qi.png)
Теперь я получаю следующее исключение в указанной строке.
Невозможно добавить объект с ключом, который уже используется.