标签: unit-of-work

如何使用工作单元和存储库模式回滚事务?

我有一个用户存储库,它可以访问所有用户数据.我还有一个工作类单元,用于管理我的存储库的连接和事务.如果我的存储库中发生错误,如何在我的工作单元上有效地回滚事务?

在我的UserRepository上创建方法.我正在使用Dapper进行DataAccess.

try
{
    this.Connection.Execute("User_Create", parameters, this.Transaction, 
        commandType: CommandType.StoredProcedure);
}
catch (Exception)
{
    //Need to tell my unit of work to rollback the transaction.                
}
Run Code Online (Sandbox Code Playgroud)

我将在我的工作单元构造函数中创建的连接和事务传递给我的存储库.以下是我工作单位的财产.

public UserRepository UserRepository
{
    get
    {
        if (this._userRepository == null)
            this._userRepository = 
                new UserRepository(this._connection, this._transaction);
        return this._userRepository;
    }
}
Run Code Online (Sandbox Code Playgroud)

我希望找到最好的方法.

*更新* 在对工作单元模式进行更多研究后,我认为我在我的例子中使用它完全错误.

c# ado.net transactions repository unit-of-work

3
推荐指数
1
解决办法
3423
查看次数

准备工作单元上的多个EF上下文 - TransactionScope

我正在考虑实现处理多个数据源的单个工作单元的选项 - 实体框架.我想出了一个尝试性的方法 - 现在处理一个单一的背景 - 但它显然不是一个好主意.

如果我们要分析下面的代码,你会认为这是一个糟糕的实现吗?交易范围的生命周期是否存在潜在问题?

当然,如果我们用不同的上下文包装事务范围,如果第二个context.SaveChanges()失败,我们将被覆盖...

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Transactions;

    namespace ConsoleApplication2
    {
        class Program
        {
            static void Main(string[] args)
            {
                using(UnitOfWork unitOfWork = new UnitOfWork())
                {

                    var repository = new EmployeeRepository(unitOfWork);

                    var employee = repository.CreateOrGetEmployee("Whatever Name");

                    Console.Write(employee.Id);

                    unitOfWork.SaveChanges();
                }
            }
        }

        class UnitOfWork : IDisposable
        {
            TestEntities _context;
            TransactionScope _scope;
            public UnitOfWork()
            {
                _scope = new TransactionScope();
                _context = new TestEntities();
            }

            public void SaveChanges()
            {
                _context.SaveChanges();
                _scope.Complete();
            }

            public …
Run Code Online (Sandbox Code Playgroud)

entity-framework transactions transactionscope unit-of-work

3
推荐指数
1
解决办法
6066
查看次数

如何将存储库注入UnitOfWork?

我已经实现了我的UnitOfWork,以便它保留对所有存储库的引用.

public interface IUnitOfWork
{
   void Commit();
   void RollBack();
}

public interface IMyUnitOfWork : IUnitOfWork
{
   IFooRepository Foos { get; }
   IBarRepository Bars { get; }
   // Other repositories ...
}
Run Code Online (Sandbox Code Playgroud)

请注意,存储库实现了一般类型的存储库接口.

public interface IFooRepository : IRepository<Entities.Foo>
{
    // FooRepository specific methods goes here.
}

public interface IRepository<T> : IRepository
    where T : class
{
}
Run Code Online (Sandbox Code Playgroud)

现在我该如何将这些存储库注入我的UnitOfWork.当然我希望它们具有延迟加载行为.例如:

public class ConcreteUnitOfWork : IMyUnitOfWork
{
   private readonly IUnityContainer unityContainer;
   private IFooRepository fooRepository;

   public ConcreteUnitOfWork(IUnityContainer unityContainer)
   {
      this.repositoryFactory = repositoryFactory;
   }

   public IFooRepository …
Run Code Online (Sandbox Code Playgroud)

dependency-injection repository unit-of-work

3
推荐指数
1
解决办法
312
查看次数

实体框架5工作单元模式 - 我应该在哪里调用SaveChanges?

如果这似乎是一个重复的问题,请提前道歉.这个问题是我能找到的最接近的问题,但它并没有真正解决我所面临的问题.

我在ASP.NET MVC4应用程序中使用Entity Framework 5并尝试实现工作单元模式.

我的工作单元类实现IDisposable并包含我的 - DbContext派生对象上下文类的单个实例,以及许多存储库,每个存储库都派生一个通用基础存储库类,它公开了所有常见的存储库功能.

对于每个HTTP请求,Ninject创建Unit of Work类的单个实例并将其注入控制器,并在请求完成时自动处理它.

由于EF5抽象出数据存储并且Ninject管理对象上下文的生命周期,因此它似乎是使用代码访问内存中实体对象而不需要明确管理其持久性的完美方式.换句话说,为了最佳地分离关注点,我设想我的控制器操作方法能够使用和修改存储库数据,而无需SaveChanges事后显式调用.

我实现这个想法的第一次(naiive)尝试SaveChanges在每个修改数据的存储库基类方法中调用.当然,我很快就意识到这不是性能优化的(特别是在对同一方法进行多次连续调用时),也不适应动作方法直接修改从存储库检索的对象的属性的情况.

所以,我改进了我的设计,以消除这些过早的调用,SaveChanges并在处理工作单元实例时用一个调用替换它们.这似乎是MVC中工作单元模式最干净的实现,因为工作单元自然是作用于请求的.

不幸的是,在构建了这个概念之后,我发现了它的致命缺陷 - 事实上,添加到或删除的对象在被调用之前DbContext不会被反射,甚至在本地不会被反射SaveChanges.

那么,您对消费代码应该能够使用对象而不明确地持久化它的想法有何看法?而且,如果这个想法似乎有效,那么用EF5实现它的最佳方法是什么?

非常感谢你的建议,

蒂姆

更新:根据@ Wahid的回复,我在下面添加了一些测试代码,其中显示了消费代码显式调用必不可少的一些情况SaveChanges:

var unitOfWork = _kernel.Get<IUnitOfWork>();
var terms = unitOfWork.Terms.Entities;

// Purge the table so as to start with a known state 
foreach (var term in terms)
{
    terms.Remove(term);
}

unitOfWork.SaveChanges();

Assert.AreEqual(0, terms.Count());

// Verify that additions are …
Run Code Online (Sandbox Code Playgroud)

entity-framework savechanges unit-of-work repository-pattern asp.net-mvc-4

3
推荐指数
1
解决办法
3244
查看次数

具有工作单元,自动映射器和通用存储库的MVC存储库

我一直在寻找一些博客文章来尝试为以下要求创建一个合适的解决方案,但我似乎无法将它们拼凑在一起.希望完全有人能提供帮助.

我一直在使用Repository模式和使用Automapper的接口......这是一个精简的例子:

public class BookingRepository : IBookingRepository
{
    Entities context = new Entities();

    public IEnumerable<BookingDto> GetBookings
    {
        get { return Mapper.Map<IQueryable<Booking>, IEnumerable<BookingDto>>(context.Bookings); }
    }

    public BookingDto GetBookingWithProduct(Guid bookingId)
    {
        return Mapper.Map<BookingDto>(context.Bookings.Include(c => c.Products).SingleOrDefault(c => c.BookingId == bookingId));
    }

    public void Update(BookingDto bookingDto)
    {
        var booking = Mapper.Map<Booking>(bookingDto);
        context.Entry(booking).State = EntityState.Modified;
    }

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

    public void Dispose()
    {
        context.Dispose();
    }
}

public interface IBookingRepository : IDisposable
{
    IEnumerable<BookingDto> GetBookings { get; }
    BookingDto GetBooking(Guid bookingId);  
    void Update(BookingDto …
Run Code Online (Sandbox Code Playgroud)

asp.net-mvc unit-of-work repository-pattern automapper entity-framework-5

3
推荐指数
1
解决办法
3833
查看次数

GenericRepository模式更新方法

我正在尝试使用unitofwork和存储库模式,并且我有以下"更新"方法,如果我替换表行(id,color,year)中的所有元素,它可以正常工作.

public virtual void Update(TEntity entityToUpdate)
{
    dbSet.Attach(entityToUpdate);
    (entityToUpdate).State = EntityState.Modified;
}
Run Code Online (Sandbox Code Playgroud)

但我想更新我传递的特定列(id和color).它会覆盖其他元素(年份).

例如,我的Cars表中有一个数据库记录:

Id = 1,
color = "red"
year = 2010
Run Code Online (Sandbox Code Playgroud)

如果我更新它...

var location = new Car
{
    Id = 1,
    color = "blue"
};


unitOfWork.CarRepository.Update(car);
Run Code Online (Sandbox Code Playgroud)

记录现在是:

Id = 1,
color = "blue"
year = null 
Run Code Online (Sandbox Code Playgroud)

我怎样才能重写我的通用存储库方法来改变我提供的东西呢?(即保持年份值)

c# asp.net-mvc unit-of-work repository-pattern

3
推荐指数
1
解决办法
2537
查看次数

使用DbContext和DbSet而不是实现存储库和工作单元

我看过很多关于实现存储库和工作单元的文章.我还看过有关如何添加额外复杂性的文章,因为DbContext已经在使用存储库和工作单元模式.

我将重构一个几乎每个实体都有一个存储库的应用程序,并希望尽可能多地删除复杂性.

任何人都可以解释/提供文章/博客/等链接,解释如何使用DbContext而不是我自己的存储库?

asp.net-mvc entity-framework unit-of-work repository-pattern

3
推荐指数
1
解决办法
3362
查看次数

架构分层和工作单元模式

我试图找出建筑/分层和工作单元的良好实践.

我们使用C#编写MVC前端应用程序.目前的正常结构是:

MVC服务/域层存储库层EF6

MVC只是简单地调用服务,(这里没有逻辑).该服务包含所有域逻辑.存储库使用EF6处理数据访问.在EF之上拥有存储库层的主要三个原因是:

1)单一责任(SRP),服务处理业务关心的内容,存储库处理获取和保存数据.使用存储库意味着它们不会混合到同一个方法中.2)测试,它使存储库更容易.(我知道你现在可以模拟dbcontext,老实说还没有尝试过这种方法).3)从域中抽象出EF,因为它并不真正关心它,(尽管这是一个非常微弱的争论).

我们将为系统的不同部分提供单独的服务和存储库,例如:

1)CustomerService 2)InvoiceService 3)OrdersService

每个存储库都有自己的实例(即没有通用存储库),允许我们准确编辑我们想要的内容并创建返回我们想要的查询,而不是获取非常大的对象或进行大量的单独调用(并避免必须通过)在很多领域包括来自域的州.

这种结构通常很有效.我们发现服务层类有时会非常大(最终破坏SRP).认为我们应该最终将它们分成子服务.如果是CustomerService,可能会成为CustomerQueryService和CustomerAdminService.我们还发现这种结构有助于存储库,因为我们的一些查询最终变得非常大,将数据转换为正确的格式,而不是拉出比所需更多的数据.

对我来说,当你想要使用交易的时候.如果我将每个存储库转换为一个工作存储库(我认为),这仍然可以工作.当您需要执行跨越两个或更多服务的操作时,会出现此问题.例如,创建订单可能还需要调用发票服务来创建发票.但如果出于某种原因,如果第二部分失败,您也会想要回滚订单并向客户端返回有用的错误.

我不确定如何实现这个,或者如果这是一个坏主意.我如何设置允许多个服务和存储库(分离囚犯和SRP)的工作单元模式?

architecture unit-of-work repository-pattern

3
推荐指数
1
解决办法
464
查看次数

Martin Fowler的POEAA工作单位是反模式吗?

从POEAA一书中,Martin Fowler介绍了这个工作单元的概念.如果你想拥有自动提交系统,你的域模型使用工作单元将自己标记为新的,脏的,删除的或清理的,它可以很好地工作.然后,您只需要调用UnitofWork.commit(),即可保存所有模型更改.以下是具有此类方法的域模型类:

public abstract class DomainModel{

    protected void markNew(){
        UnitOfWork.getCurrent().registerNew(this);
    }

    protected void markDirty(){
        UnitOfWork.getCurrent().registerDirty(this);
    }

    protected void markRemoved(){
        UnitOfWork.getCurrent().registerRemoved(this);
    }        

    protected void markClean(){
        UnitOfWork.getCurrent().registerClean(this);
    }
} 
Run Code Online (Sandbox Code Playgroud)

通过此实现,您可以通过业务逻辑方法将域模型标记为任何保存状态:

public class Message extends DomainModel{

    public void updateContent(User user, string content){
        // This method update message content if the the message posted time is not longer than 24 hrs, and the user has permission to update messate content.
        if(!canUpdateContent(user) && timeExpired()) throw new IllegalOperationException("An error occurred, cannot update content.");
        this.content = content; …
Run Code Online (Sandbox Code Playgroud)

oop orm domain-driven-design unit-of-work domain-model

3
推荐指数
2
解决办法
2424
查看次数

无法访问ABP中的Hangfire经常性作业上的已处置对象(在DbContext上)错误

我正在尝试在应用程序启动时设置Hangfire经常性作业,但是在该作业中,如果我尝试使用IRepositoryInjection,它将在尝试执行查询时给出与DbContext相关的错误:

System.ObjectDisposedException
Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances. Object name: 'WsApplicationDbContext'. …
Run Code Online (Sandbox Code Playgroud)

c# unit-of-work hangfire .net-core aspnetboilerplate

3
推荐指数
1
解决办法
770
查看次数