Обновление сущности с использованием Linq-to-SQL - присоединение не новой сущности - PullRequest
4 голосов
/ 07 мая 2011

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

Теперь я получаю следующее исключение в указанной строке.

Невозможно добавить объект с ключом, который уже используется.

1 Ответ

0 голосов
/ 08 мая 2011

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

Пример метода отсоединения можно найти здесь: http://omaralzabir.com/linq_to_sql__how_to_attach_object_to_a_different_data_context/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...