2011-05-07 73 views
3

我正在嘗試編寫一個使用Linq-to-SQL與數據庫接口的程序(MS SQL Server 2008)。添加和刪​​除似乎沒問題,但我無法繞過更新。使用Linq-to-SQL更新實體 - 附加一個不是新的實體

該實體上有一個版本列,它是數據庫上的時間戳列,用於內置於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)。在TaskRepositoryDispose()方法中,我在我的數據上下文中調用了Dispose()

我也改變了Update()方法在我的Task對象上調用Detach()。我的代碼現在看起來像這樣:

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 
} 

的任務分離()方法是這樣的:

public void Detach() 
{ 
    this._Project = default(EntityRef<Project>); 
    this._Priority = default(EntityRef<Priority>); 
} 

僅供參考,我的實體是這樣的:

Database layout

我現在在所示的線上獲得以下例外。

無法添加具有已使用密鑰的實體。

回答

0

嘗試deattach從以前的數據上下文您Task對象將其連接到整體appilaction數據上下文的一個新的或使用單一實例之前...

你可以發現在這裏deattach方法: http://omaralzabir.com/linq_to_sql__how_to_attach_object_to_a_different_data_context/

+0

我已將原始帖子更新爲帶有從該鏈接找到的建議的新代碼。我現在得到了一個不同的例外。你能幫我嗎? – Stu 2011-05-08 14:36:49

+0

好的..嘗試爲每個查詢使用新的datacontext ..共享datacontext不是最好的選擇,如果你附加和deattach對象.. – 2011-05-08 22:14:42