entity-framework - 在一次事务中调用多个服务方法

标签 entity-framework entity-framework-6 transactionscope

请原谅我不太擅长 EF6。如果我犯了一些错误。请帮我改正。谢谢。

首先,我想在我的服务层中实现业务逻辑,如下所示。

public class userService
{
    void createWithCommit(User user)
    {
        MyEntityContext db= new MyEntityContext ();
        ...
        db.Users.add(user);//Add a new user entity
        ....
        Work w = new Work();
        ... 
        db.Works.add(w);//Add a new work entity
        db.savechanges();//commit the changes which will insert 2 new record . one is user . another is work.
    }
}

但在某些服务类中,我想在一个事务中调用多个其他服务方法,如下所示。

class utilService
{
    void update(SomeClass cls)
    {
        using (var tran=new TransactionScope())
        {
          userService userSvr= new userService();
          userSvr.create();//this method already include a savechanges().
          jobService jobSvr= new jobService();
          jobSvr.update();//this method may include another savechanges().
          tran.Complete();//I don't why EF6 doesn't have the Commit method. just has the Complete method.
        }

    }
}

所以我可以在 ASP.net MVC Controller 中使用它,如下所示。

class SomeController
{
    ActionResult index()
    {
        userService userSvr = new userService();
        userSvr.createWithCommit();

    }

    ActionResult util()
    {
        utilService utilSvr = new utilService ();
        userSvr.update(....);

    }
}

所以你可以看到我的想法是我想将多种服务方法包含到一个事务中。并且每个包含的服务方法可能包含也可能不包含代码 SaveChanges() (这意味着事务已提交。对吗?)。

你可以看到。在我的测试中,我尝试使用 TransactionScope 将多个服务方法包含到一个事务中。我的意思是在方法 utilService.update() 中。但在调用 SaveChanges() 后,TransactionScope 似乎不起作用。所以我的问题是:

有没有可能按照我的想法实现呢?如果有 。我应该应用什么样的模式? (我听说过 UOW 和 Repository 模式。它们是解决方案吗?谢谢。)

最佳答案

You need to implement Unit of work pattern to avoid transaction scope.Unit of Work and Repository Pattern is something used fairly widely nowadays.

UoW exposes public method Commit to store the changes.

通用存储库

public class GenericRepository<TEntity> where TEntity : class
{
    internal SchoolContext context;
    internal DbSet<TEntity> dbSet;

    public GenericRepository(SchoolContext context)
    {
        this.context = context;
        this.dbSet = context.Set<TEntity>();
    }

    public virtual IEnumerable<TEntity> Get(
        Expression<Func<TEntity, bool>> filter = null,
        Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
        string includeProperties = "")
    {
        IQueryable<TEntity> query = dbSet;

        if (filter != null)
        {
            query = query.Where(filter);
        }

        foreach (var includeProperty in includeProperties.Split
            (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
        {
            query = query.Include(includeProperty);
        }

        if (orderBy != null)
        {
            return orderBy(query).ToList();
        }
        else
        {
            return query.ToList();
        }
    }

    public virtual TEntity GetByID(object id)
    {
        return dbSet.Find(id);
    }

    public virtual void Insert(TEntity entity)
    {
        dbSet.Add(entity);
    }

    public virtual void Delete(object id)
    {
        TEntity entityToDelete = dbSet.Find(id);
        Delete(entityToDelete);
    }

    public virtual void Delete(TEntity entityToDelete)
    {
        if (context.Entry(entityToDelete).State == EntityState.Detached)
        {
            dbSet.Attach(entityToDelete);
        }
        dbSet.Remove(entityToDelete);
    }

    public virtual void Update(TEntity entityToUpdate)
    {
        dbSet.Attach(entityToUpdate);
        context.Entry(entityToUpdate).State = EntityState.Modified;
    }
}

工作单元

public class UnitOfWork : IDisposable
{
    //Context Creation in the UnitOfWork
    //This context is supplied to all Repository 
    //Hence One Commit save All Changes
    private SchoolContext context = new SchoolContext();
    private GenericRepository<Department> departmentRepository;
    private GenericRepository<Course> courseRepository;

    public GenericRepository<Department> DepartmentRepository
    {
        get
        {

            if (this.departmentRepository == null)
            {
                this.departmentRepository = new GenericRepository<Department>(context);
            }
            return departmentRepository;
        }
    }

    public GenericRepository<Course> CourseRepository
    {
        get
        {

            if (this.courseRepository == null)
            {
                this.courseRepository = new GenericRepository<Course>(context);
            }
            return courseRepository;
        }
    }

    public void Save()
    {
        context.SaveChanges();
    }

    private bool disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                context.Dispose();
            }
        }
        this.disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

使用

  //Sample Controller
 public class CourseController : Controller
   {
      //Initialize the unit of work here
      private UnitOfWork unitOfWork = new UnitOfWork();

      Public Void MyBussinessTransaction()
      {
         unitOfWork.CourseRepository.Insert(course);
         unitOfWork.DepartmentRepository.Insert(department)
         unitOfWork.Save();
      }
   }

Implementing the Repository and Unit of Work Patterns

Martin Flower explanation of UOW

关于entity-framework - 在一次事务中调用多个服务方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31943189/

相关文章:

c# - Lambda 表达式中带有 AND 运算符的 Lambda 表达式

c# - Entityframework RC1 - MetadataItem.Annotations made internal - 替代方案?

c# - 如何在C#中获取与titleNames中至少一个单词匹配的所有标题

c# - 如何查找交易状态

.net - 为什么在 .net 中使用 TransactionScopeOption.Suppress 时会忽略隔离级别

c# - 为什么 Take() 返回的行数多于指定的行数?

c# - 使用 Moq 对 Entity Framework 通用存储库进行单元测试

c# - 有没有办法打开一个不参与当前 TransactionScope 的新连接?

c# - 无法将类型 'x' 转换为类型 'y'。 LINQ to Entities 仅支持转换 EDM 原语或枚举类型

mysql - 使用 EntityFramework 6 和 MySql 的 TransactionScope