2011-09-18 10 views
2

"작업 단위"패턴으로 일반 저장소를 사용하려고합니다. 여기 Entity Framework 4 SaveChanges가 작동하지 않고 오류가 발생하지 않습니까?

내 작품의 자세한 사항

public class GenericRepository:IRepository 
{ 

    private readonly string _connectionStringName; 
    private ObjectContext _objectContext; 
    private readonly PluralizationService _pluralizer = PluralizationService.CreateService(CultureInfo.GetCultureInfo("en")); 

    public GenericRepository() 
    { 
     this._objectContext = ContextManager.CurrentFor(); 
    } 

    public void Add<TEntity>(TEntity entity) where TEntity : class 
    { 
     ((DataEntities.MyTestDBEntities)_objectContext).Countries.AddObject(new Country() { CountryName="UGANDA"}); 
     this._objectContext.AddObject(GetEntityName<TEntity>(), entity); 
    } 

    public void Update<TEntity>(TEntity entity) where TEntity : class 
    { 
     var fqen = GetEntityName<TEntity>(); 

     object originalItem; 
     EntityKey key = ObjectContext.CreateEntityKey(fqen, entity); 
     if (ObjectContext.TryGetObjectByKey(key, out originalItem)) 
     { 
      ObjectContext.ApplyCurrentValues(key.EntitySetName, entity); 
     } 
    } 

    private string GetEntityName<TEntity>() where TEntity : class 
    { 
     return string.Format("{0}.{1}", ObjectContext.DefaultContainerName, _pluralizer.Pluralize(typeof(TEntity).Name)); 
    } 

    public object Get<TEntity>() where TEntity : class 
    { 
     var entityName = GetEntityName<TEntity>(); 
     return ObjectContext.CreateQuery<TEntity>(entityName); 
    } 

    public IEnumerable<TEntity> Find<TEntity>(Expression<Func<TEntity, bool>> criteria) where TEntity : class 
    { 
     return GetQuery<TEntity>().Where(criteria); 
    } 

    private IUnitOfWork unitOfWork; 

    public ObjectContext ObjectContext 
    { 
     get { return ContextManager.CurrentFor(); } 
    } 

    public IUnitOfWork UnitOfWork 
    { 
     get 
     { 
      if (unitOfWork == null) 
      { 
       unitOfWork = new UnitOfWork(this.ObjectContext); 
      } 
      return unitOfWork; 
     } 
    } 

    public IQueryable<TEntity> GetQuery<TEntity>() where TEntity : class 
    { 
     var entityName = GetEntityName<TEntity>(); 
     return ObjectContext.CreateQuery<TEntity>(entityName); 
    } 
} 

그때 내가 UnitOfWork.cs

public class UnitOfWork:IUnitOfWork 
{ 
    private DbTransaction _transaction; 
    private ObjectContext _objectContext; 

    public UnitOfWork(ObjectContext context) 
    { 
     _objectContext = context; 
    } 

    public bool IsInTransaction 
    { 
     get { return _transaction != null; } 
    } 

    public void BeginTransaction() 
    { 
     BeginTransaction(IsolationLevel.ReadCommitted); 
    } 

    public void BeginTransaction(IsolationLevel isolationLevel) 
    { 
     if (_transaction != null) 
     { 
      throw new ApplicationException("Cannot begin a new transaction while an existing transaction is still running. " + 
              "Please commit or rollback the existing transaction before starting a new one."); 
     } 
     OpenConnection(); 
     _transaction = _objectContext.Connection.BeginTransaction(isolationLevel); 
    } 

    public void RollBackTransaction() 
    { 
     if (_transaction == null) 
     { 
      throw new ApplicationException("Cannot roll back a transaction while there is no transaction running."); 
     } 

     try 
     { 
      _transaction.Rollback(); 
     } 
     catch 
     { 
      throw; 
     } 
     finally 
     { 
      ReleaseCurrentTransaction(); 
     } 
    } 

    public void CommitTransaction() 
    { 
     if (_transaction == null) 
     { 
      throw new ApplicationException("Cannot roll back a transaction while there is no transaction running."); 
     } 

     try 
     { 
      _objectContext.SaveChanges(); 
      _transaction.Commit(); 
     } 
     catch 
     { 
      _transaction.Rollback(); 
      throw; 
     } 
     finally 
     { 
      ReleaseCurrentTransaction(); 
     } 
    } 

    public void SaveChanges() 
    { 
     if (IsInTransaction) 
     { 
      throw new ApplicationException("A transaction is running. Call BeginTransaction instead."); 
     } 
     _objectContext.SaveChanges(SaveOptions.AcceptAllChangesAfterSave); 
    } 

    public void SaveChanges(SaveOptions saveOptions) 
    { 
     if (IsInTransaction) 
     { 
      throw new ApplicationException("A transaction is running. Call BeginTransaction instead."); 
     } 
     _objectContext.SaveChanges(saveOptions); 
    } 

    /// <summary> 
    /// Releases the current transaction 
    /// </summary> 
    private void ReleaseCurrentTransaction() 
    { 
     if (_transaction != null) 
     { 
      _transaction.Dispose(); 
      _transaction = null; 
     } 
    } 

    private void OpenConnection() 
    { 
     if (_objectContext.Connection.State != ConnectionState.Open) 
     { 
      _objectContext.Connection.Open(); 
     } 
    } 

    /// <summary> 
    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. 
    /// </summary> 
    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    /// <summary> 
    /// Disposes the managed and unmanaged resources. 
    /// </summary> 
    /// <param name="disposing"></param> 
    private void Dispose(bool disposing) 
    { 
     if (!disposing) 
      return; 

     if (_disposed) 
      return; 

     ReleaseCurrentTransaction(); 

     _disposed = true; 
    } 
    private bool _disposed; 
} 

와 변경 및 기타 커밋 트랜잭션을 저장 리디렉션됩니다 만 내 ContextManager 클래스를 통해 내 컨텍스트를 얻고있다 :

public class ContextManager 
{ 
    /// <summary> 
    /// The default connection string name used if only one database is being communicated with. 
    /// </summary> 
    public static readonly string DefaultConnectionStringName = "DefaultDb"; 

    /// <summary> 
    /// An application-specific implementation of IObjectContextStorage must be setup either thru 
    /// <see cref="InitStorage" /> or one of the <see cref="Init" /> overloads. 
    /// </summary> 
    private static IObjectContextStorage Storage { get; set; } 

    /// <summary> 
    /// Maintains a dictionary of object context builders, one per database. The key is a 
    /// connection string name used to look up the associated database, and used to decorate respective 
    /// repositories. If only one database is being used, this dictionary contains a single 
    /// factory with a key of <see cref="DefaultConnectionStringName" />. 
    /// </summary> 
    // private static Dictionary<string, IObjectContextBuilder<ObjectContext>> objectContextBuilders = new Dictionary<string, IObjectContextBuilder<ObjectContext>>(); 

    private static object _syncLock = new object(); 

    /// <summary> 
    /// Used to get the current object context session if you're communicating with a single database. 
    /// When communicating with multiple databases, invoke <see cref="CurrentFor()" /> instead. 
    /// </summary> 
    public static ObjectContext Current 
    { 
     get { return CurrentFor(); } 
    } 

    /// <summary> 
    /// Used to get the current ObjectContext associated with a key; i.e., the key 
    /// associated with an object context for a specific database. 
    /// 
    /// If you're only communicating with one database, you should call <see cref="Current" /> instead, 
    /// although you're certainly welcome to call this if you have the key available. 
    /// </summary> 
    public static ObjectContext CurrentFor() 
    { 
     ObjectContext context = null; 
     lock (_syncLock) 
     {    
      if (context == null) 
      { 
       context =new TestDAL.DataEntities.MyTestDBEntities(); 
       //Storage.SetObjectContextForKey(key, context); 
      } 
     } 

     return context; 
    } 

    /// <summary> 
    /// This method is used by application-specific object context storage implementations 
    /// and unit tests. Its job is to walk thru existing cached object context(s) and Close() each one. 
    /// </summary> 
    public static void CloseAllObjectContexts() 
    { 
     if (CurrentFor().Connection.State == System.Data.ConnectionState.Open) 
     { 
      CurrentFor().Connection.Close(); 
     } 
    } 
} 

엔티티 검색이 가능하지만 데이터베이스에 오류나 업데이트를 표시하지 않는 엔티티를 만들고 싶습니다.

실마리가 도움이 될 것입니다.

답변

3

public static ObjectContext CurrentFor() 메서드는 항상 새로운 컨텍스트를 만듭니다. 그리고 당신의 쿼리는

public ObjectContext ObjectContext 
{ 
    get { return ContextManager.CurrentFor(); } 
} 

은 그러므로 당신이 ObjectContext의 여러 인스턴스를 사용하는 ObjectContext 속성을 사용하고 있습니다. ObjectContext의 다른 인스턴스 SaveChanges()으로 전화를 걸고 있습니다. 따라서 변경 사항은 유지되지 않습니다.

UnitOfWork에서와 같이 트랜잭션을 명시 적으로 처리하지 마십시오. ObjectContext이 해당 부분을 담당하게됩니다.

디자인은 복잡한 추상화입니다. 프레임 워크를 그대로 사용하거나 이미 테스트 된 간단한 저장소 패턴을 찾으십시오.

관련 문제