2011-05-07 41 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