我正在尝试编写一个使用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)
。在TaskRepository
的Dispose()
方法中,我在我的数据上下文中调用了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>);
}
仅供参考,我的实体是这样的:
我现在在所示的线上获得以下例外。
无法添加具有已使用密钥的实体。
我已将原始帖子更新为带有从该链接找到的建议的新代码。我现在得到了一个不同的例外。你能帮我吗? – Stu 2011-05-08 14:36:49
好的..尝试为每个查询使用新的datacontext ..共享datacontext不是最好的选择,如果你附加和deattach对象.. – 2011-05-08 22:14:42