实体框架4 SaveChanges不工作,不会抛出任何错误? [英] Entity Framework 4 SaveChanges not working and not throwing any error?

查看:122
本文介绍了实体框架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添加< TEntity>(TEntity entity)其中TEntity:class
{
((DataEntities.MyTestDBEntities)_objectContext).Countries.AddObject Country(){CountryName =UGANDA});
this._objectContext.AddObject(GetEntityName< TEntity>(),entity);
}

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

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

私有字符串GetEntityName< TEntity>()其中TEntity:class
{
return string.Format({0} 1},ObjectContext.DefaultContainerName,_pluralizer.Pluralize(typeof(TEntity).Name));
}

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

public IEnumerable< TEntity>查找< TEntity>(表达式< Func< TEntity,bool>>标准)其中TEntity:class
{
返回GetQuery< TEntity>()
}

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>()其中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现有的交易仍在运行时,无法开始新的交易。+
在开始新的交易之前,请提交或回滚现有的交易。
}
OpenConnection();
_transaction = _objectContext.Connection.BeginTransaction(isolationLevel);
}

public void RollBackTransaction()
{
if(_transaction == null)
{
throw new ApplicationException(Can not roll在没有事务运行的情况下返回事务。);
}

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

public void CommitTransaction()
{
if(_transaction == null)
{
throw new ApplicationException(没有事务运行时不能回滚事务);
}

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



public void SaveChanges()
{
if(IsInTransaction)
{
throw new ApplicationException(一个事务正在运行,调用BeginTransaction。);
}
_objectContext.SaveChanges(SaveOptions.AcceptAllChangesAfterSave);
}

public void SaveChanges(SaveOptions saveOptions)
{
if(IsInTransaction)
{
throw new ApplicationException(A transaction is运行,调用BeginTransaction。);
}
_objectContext.SaveChanges(saveOptions);
}

///< summary>
///发布当前事务
///< / summary>
private void ReleaseCurrentTransaction()
{
if(_transaction!= null)
{
_transaction.Dispose();
_transaction = null;
}
}

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

///< summary>
///执行与释放,释放或重置非托管资源相关联的应用程序定义任务。
///< / summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

///< summary>
///配置托管和非托管资源。
///< / summary>
///< param name =disposal>< / param>
private void Dispose(bool disposal)
{
if(!disposal)
return;

if(_disposed)
return;

ReleaseCurrentTransaction();

_disposed = true;
}
private bool _disposed;
}

我通过我的 ContextManager class:

  public class ContextManager 
{
///< summary> ;
///如果只传送一个数据库,则使用默认连接字符串名称。
///< / summary>
public static readonly string DefaultConnectionStringName =DefaultDb;

///< summary>
/// IObjectContextStorage的应用程序特定实现必须通过
///< see cref =InitStorage/>或者重载。
///< / summary>
private static IObjectContextStorage Storage {get;组; }

///< summary>
///维护对象上下文构建器的字典,每个数据库一个。关键是用于查找关联数据库的
///连接字符串名称,用于装饰相应的
///存储库。如果仅使用一个数据库,则该字典包含一个
///工厂,键值为< see cref =DefaultConnectionStringName/> ;.
///< / summary>
//私有静态字典< string,IObjectContextBuilder< ObjectContext>> objectContextBuilders = new Dictionary< string,IObjectContextBuilder< ObjectContext>>();

私有静态对象_syncLock = new object();

///< summary>
///如果您正在与单个数据库通信,则用于获取当前对象上下文会话。
///当与多个数据库通信时,调用< see cref =CurrentFor()/>代替。
///< / summary>
public static ObjectContext当前
{
get {return CurrentFor(); }
}

///< summary>
///用于获取与一个键相关联的当前ObjectContext;即与特定数据库的对象上下文相关联的键
///。
///
///如果您只与一个数据库进行通信,您应该调用< see cref =Current/>相反,
///虽然如果您有钥匙可用,您当然欢迎来电。
///< / summary>
public static ObjectContext CurrentFor()
{
ObjectContext context = null;
lock(_syncLock)
{
if(context == null)
{
context = new TestDAL.DataEntities.MyTestDBEntities();
//Storage.SetObjectContextForKey(key,context);
}
}

返回上下文;
}

///< summary>
///这个方法被应用程序特定的对象上下文存储实现
///和单元测试使用。它的工作是通过现有的缓存对象上下文和关闭()每一个。
///< / summary>
public static void CloseAllObjectContexts()
{
if(CurrentFor()。Connection.State == System.Data.ConnectionState.Open)
{
CurrentFor() .Connection.Close();
}
}
}

它让我检索实体,但是当我想创建一个实体时,它不会显示错误,也不显示数据库中的任何更新。



任何线索都将有所帮助。

解决方案

您的 public static ObjectContext CurrentFor()方法将始终创建一个新的上下文。您的查询使用 ObjectContext 属性

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

因此,您正在使用多个 ObjectContext 。您正在调用 ObjectContext 的另一个实例的 SaveChanges()。所以没有变化会持续下去。



不要像在 UnitOfWork 中那样明确处理事务。

您的设计是一个复杂的抽象。尝试使用框架,或者找到一个已经被测试过的简单的Repository模式。


I am trying to use my generic repository with a "unit of work" pattern.

Here is my work details

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);
    }
}

then I will redirect save changes and other committing the transaction with 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;
}

and I am getting my context through my ContextManager class:

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();
        }
    }
}

it gives me retrieval of entities, but when I want to create an entity it doesn't shows nay error nor any update in the database.

Any clue will be helpful.

解决方案

Your public static ObjectContext CurrentFor() method will always create a new context. And your queries are using the ObjectContext property

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

Hence you are using multiple instances of ObjectContext. You are calling SaveChanges() of a different instance of ObjectContext. So no changes will be persisted.

Do not handle the transactions explicitly as you did in UnitOfWork. The ObjectContext will do that part.

Your design is a complicated abstraction. Try to use the framework as it is or find a simple Repository pattern which has already being tested an used.

这篇关于实体框架4 SaveChanges不工作,不会抛出任何错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆