我找到了解决我的问题。
当我试图附加一个已经附加到datacontext的实体时,发生了异常,这是因为我的Update()方法中没有指示实体是否已经附加到数据上下文方法使用。
当我删除附件时,我没有得到异常,但实体有时没有udpated(如果datacontext是新的)。
所以我想如何在这两种冲突情况之间架起桥梁,解决方案就是TransactionScope。
我创建了TransactionScope类,允许方法加入和离开范围。
Join()方法创建新的数据上下文并初始化使用计数器,因此对此方法的任何连续调用都会将此计数器加1。
Leave()方法递减使用计数器,当它到达零时,将处理datacontext。
还有一个属性返回数据上下文(而不是每个方法来尝试获取自己的上下文)。
我改变需要从我的问题是什么描述数据上下文的方法:
_myTranscationScope.Join();
try
{
var context = _myTransactionScope.Context;
//Do some database operation for example:
context.User.GetByKey("username");
}
finally
{
_myTranscationScope.Leave();
}
另外我overrided在DataContext的Dispose方法和移动的实体存在的分离,而不是这样做在每种方法中。
所有我需要确保的是,我有正确的交易范围,并确保每个呼叫的加盟也叫离开(甚至在例外)
现在,这使我的代码可以完美兼容所有方案(包括单个数据库操作,复杂事务,使用序列化对象)。
这里是TransactionScope类的代码(我删除依赖于我的工作项目行代码,但它仍然是完全工作的代码):
using System;
using CSG.Games.Data.SqlRepository.Model;
namespace CSG.Games.Data.SqlRepository
{
/// <summary>
/// Defines a transaction scope
/// </summary>
public class TransactionScope :IDisposable
{
private int _contextUsageCounter; // the number of usages in the context
private readonly object _contextLocker; // to make access to _context thread safe
private bool _disposed; // Indicates if the object is disposed
internal TransactionScope()
{
Context = null;
_contextLocker = new object();
_contextUsageCounter = 0;
_disposed = false;
}
internal MainDataContext Context { get; private set; }
internal void Join()
{
// block the access to the context
lock (_contextLocker)
{
CheckDisposed();
// Increment the context usage counter
_contextUsageCounter++;
// If there is no context, create new
if (Context == null)
Context = new MainDataContext();
}
}
internal void Leave()
{
// block the access to the context
lock (_contextLocker)
{
CheckDisposed();
// If no one using the context, leave...
if(_contextUsageCounter == 0)
return;
// Decrement the context usage counter
_contextUsageCounter--;
// If the context is in use, leave...
if (_contextUsageCounter > 0)
return;
// If the context can be disposed, dispose it
if (Context.Transaction != null)
Context.Dispose();
// Reset the context of this scope becuase the transaction scope ended
Context = null;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
lock (_contextLocker)
{
if (_disposed) return;
if (disposing)
{
if (Context != null && Context.Transaction != null)
Context.Dispose();
_disposed = true;
}
}
}
private void CheckDisposed()
{
if (_disposed)
throw new ObjectDisposedException("The TransactionScope is disposed");
}
}
}
上找到一个解决办法干得好:) – 2011-07-07 17:39:46