- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在从事一个 Web API 项目(ninject、原始 sql 查询、存储库模式、UoW 模式)我几乎在所有地方都检查过一篇文章,该文章描述了使用不使用 Entity Framework 的简单数据库事务实现 UoW(纯 SQL 请求和 SqlConnection 等...),但找不到任何内容。
我遇到的问题如下。我有一个 Web API,它具有与存储库一起工作的 Controller ,而存储库又通过 UoW 注入(inject)到它们中的 DBManager 类来处理数据库。
让我们假设我在存储库中有 2 个方法,每个方法都更新数据库中的数据:
方法 1 - 更新工单(添加客户的帖子)。方法 2 - 更新工单的状态(仅当发布成功时)。
这些方法可以一个接一个地调用,或者单独调用,例如,可以从某个其他方法调用方法 2,例如,在票证关闭之后。
方法一,在更新DB之前通过DBManager创建一个事务。然后它更新 DB 并调用 Method2 来做他的事情。方法 2,因为它也可以作为独立方法调用,所以也在更新数据库之前启动事务。执行查询时,它会提交事务并返回到 Method1。 Method1 在这个阶段也提交事务,因为没有异常,它希望保留对数据库所做的更改。但是,它不能,因为更改已由 Method2 提交。
所以 Action 图类似于下面的图:
Method1()
DBManager.BeginTransaction() - begins new transaction
update DB - adds post to the ticket
Method2() - calls method 2 to update ticket status
DBManager.BeginTransaction() - returns transaction started by Method1()
update DB - updates ticket status
DBManager.CommitTransaction() - commits transaction
return
DBManager.CommitTransaction() - commits transaction to save ALL changes but can't since transaction was already committed.
如果我需要在票证状态更新后调用其他方法,那么方法将使用全新的数据集,因为更改已通过 Method2() 提交到数据库中。
我开始考虑如何解决这个问题,但找不到任何东西。我已经阅读了有关 TransactionScope 的内容,并认为我可以做这样的事情:
public class UnitOfWork : IUnitOfWork, IDisposable
{
/// <summary>
/// DB context.
/// </summary>
private IDBManager _dbManager;
/// <summary>
/// Repository provider class which can create repositories on demand.
/// </summary>
private IRepositoryProvider _repositoryProvider;
private TransactionScope _transaction;
public UnitOfWork(IDBManager dbManager, IRepositoryProvider repoProvider)
{
_dbManager = dbManager;
_repositoryProvider = repoProvider;
}
public T GetRepository<T>()
{
if (_transaction == null)
_transaction = new TransactionScope();
return _repositoryProvider.Create<T>(_dbManager);
}
public void Save()
{
_transaction.Complete();
}
public void Dispose()
{
_transaction.Dispose();
}
}
在这种情况下,TransactionScope 将在我创建我的第一个存储库时开始,然后我可以在我的 Controller 中调用保存,如下所示:
public TicketPost AddTicketPost(int tid, TicketPost update)
{
TicketPost post = Uow.GetRepository<ITicketsRepository>().AddPost(tid, update);
Uow.Save();
return post;
}
但是,这意味着将为任何操作创建 TransactionScope - 选择/更新/删除,并且它将从创建第一个存储库的那一刻(即使我可能不需要它)一直持续到交易发生的那一刻要么处置要么完成。
另一种解决方案是使用 DBManager 的事务并从 Controller 调用 BeginTransaction,并在我需要时调用 Commit 或 Rollback。像这样:
Uow.BeginTransaction();
try
{
TicketPost post = Uow.GetRepository<ITicketsRepository>().AddPost(tid, update);
}
catch (Exception e)
{
Uow.RollbacTransaction();
}
Uow.CommitTransaction();
但我不太喜欢这种方法。在第一种情况下,我需要捕获异常,这些异常会冒泡到我的 ExceptionsHandler,它会创建对客户端的响应消息。另外,我认为 Controller 是一个中间人,它收到请求并说“嘿,存储库,这是数据,我已经检查过了,做你的事然后给我回电话。”。当它收到来自存储库的“调用”时,它可能会做一些与数据无关的事情,比如发送电子邮件。我喜欢当 Controller 不需要在同一个存储库中一个接一个地调用方法并考虑它需要做的事情来完成工作时,例如:
取而代之的是, Controller 要求存储库处理票证更新并等待它可以发送电子邮件:
我处理 Controller 和存储库的方式可能是错误的。如果我错了,请纠正我。
我希望有人能给我指点资源,或者可能有人具有类似的设置并且已经找到了针对这种情况(交易问题)的解决方案。
如有任何帮助,我们将不胜感激。非常感谢您。
最佳答案
如果我没理解错的话,您想要一种方法来避免创建不需要的事务?
为此,我建议您创建一个 BaseUnitOfWork 类型和两个其他类型:ReadOnlyUnitOfWork 和 ReadWriteUnitOfWork。
然后,在选择内容时您将只使用 ReadOnly,而在您需要两者时使用 ReadWrite。
C# 中的框架类似于。
public class BaseUnitOfWork // YOUR INTERFACES HERE
{
/// <summary>
/// DB context.
/// </summary>
private IDBManager _dbManager;
/// <summary>
/// Repository provider class which can create repositories on demand.
/// </summary>
private IRepositoryProvider _repositoryProvider;
public BaseUnitOfWork(IDBManager dbManager, IRepositoryProvider repoProvider)
{
_dbManager = dbManager;
_repositoryProvider = repoProvider;
}
public T GetRepository<T>()
{
return _repositoryProvider.Create<T>(_dbManager);
}
}
public class ReadOnlyUnitOfWork : BaseUnitOfWork
{
public ReadOnlyUnitOfWork(IDBManager dbManager, IRepositoryProvider repoProvider) : base(dbManager,repoProvider)
{
_dbManager = dbManager;
_repositoryProvider = repoProvider;
}
}
public class ReadWriteUnitOfWork : BaseUnitOfWork// YOUR INTERFACES HERE
{
private TransactionScope _transaction;
public ReadWriteUnitOfWork(IDBManager dbManager, IRepositoryProvider repoProvider) : base(dbManager,repoProvider)
{
if (_transaction == null)
_transaction = new TransactionScope();
}
public void Save()
{
_transaction.Complete();
}
public void Dispose()
{
_transaction.Dispose();
}
}
我已经在几个项目中成功地使用了这个策略。
此策略的好处在于您遵守 SOLID (http://en.wikipedia.org/wiki/SOLID_(object-oriented_design)) 设计中的 S:单一职责。
一个类负责处理带有事务的数据库操作,而另一个只处理无事务操作。
此外,您必须了解工作 block 单元应该快速(执行时)并且(如果可能)代码量小(作为最佳实践)。
因此,您可以像这样使用它:
using( IReadWriteUnitOfWork uow = InjectionFramework.ResolveDependencyOfType<IReadWriteUnitOfWork>() )
{
//do your database stuff here, try to keep it simple.
//after doing everything, you **commit** the transaction (in your case, you save)
uow.Save();
}
使用命令的好处是,在您完成这段代码后,它会自动调用您的 dispose 方法。
关于没有带数据库事务或 TransactionScope 的 EF 的 C# UnitOWork 实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21480889/
我有一个应用程序,我想将多个数据库保存到一个事务中。如果他们中的任何一个失败了,我想把整个事情都推回去。但是,我想在回滚事务之前知道其中哪些失败(或成功)。 我有一个带有内部循环的外部 Transac
我刚刚开始玩 Dapper。到目前为止我很喜欢它。 dapper 不能与 TransactionScope 一起使用吗?我注意到,即使我从不调用 TransactionScope.Complete,我
您好首先感谢您对这个问题的关注;有没有办法在c#中实现这样的事务 using (Transactionscope x=new Transactionscope ()) { Thead A()=>
这是使用事务范围的正确方法吗: 我有一个代表事物的一部分的对象: public class ThingPart { private DbProviderFactory connectionFa
我正在尝试找到在使用 NHibernate 的 Web 应用程序中处理事务的最佳解决方案。 我们使用 IHttpModule 并在 HttpApplication.BeginRequest 我们打开一
我面临以下问题: 在我的项目中,我在应用程序正在使用的同一个数据库中进行了错误登录。这意味着,如果发生错误,那么在每个 catch 中,都会将错误存储到 DB 中。 然而,问题是在使用事务时。发生错误
我想知道在处理多线程时如何正确使用 TransactionScope 类? 我们在主线程中创建一个新的作用域,然后生成几个工作线程,我们希望它们参与主作用域,因此,如果作用域从未完成,则在每个工作线程
任何人都可以给我一个关于使用 TransactionScope 和 NHibernate 的快速概述吗?我需要对 session /IEnlistmentNotification/等做一些特别的事情吗
如果我执行以下操作: Using scope = New TransactionScope() entries.Content.ReadAs(Of IList(Of WebMaint
当 TransactionScope 首次推出时,我在让它在我的开发机器 (XP) 和我们的数据库服务器 (Windows Server 2003) 之间工作时遇到了一些严重的问题。 当我进一步研究时
我在基于 Silverlight 和 RIA 服务的项目中使用 TransactionScope 类。每次我需要保存一些数据时,我都会创建一个 TransactionScope 对象,使用 Oracl
TransactionScope 是否适用于封闭的数据库连接? using (var transaction = new TransactionScope(TransactionScopeOption
我有两个 PL/SQL 存储过程,每个过程都处理自己的事务(开始/提交和发生错误时的回滚)。从 .Net 代码我调用这两个 SP,如下所示。 using (TransactionScope ts
我在我的应用程序中使用了 TransactionScope 类,因为我需要以交互方式、自然地执行一些操作(要么全部成功,要么全都不成功)。 由于此操作不仅与数据库相关,我通过实现 IEnlistmen
您好,有没有办法检查使用 TransactionScope 的事务是提交还是回滚? 最佳答案 在处理 TransactionScope 之前,实际的提交不会发生。如果 Commit 由于任何原因失败,
我有一个 Web 应用程序,许多用户在任何给定时刻都在使用它。从数据库的角度来看,他们在系统中移动时不断地从任意数量的表中写入和读取数据。此外,我们还有许多将数据导入该系统的流程。 今天,在调试导入过
我正在开发一个使用 C# 和 SQL Server 作为数据库的 .NET Web 应用程序,我是这两种技术的新手。当我尝试同时保存大量信息时遇到问题。 我的代码很简单: SqlConnectio
您好,我在我的应用程序的多个位置使用了 TransactionScope。喜欢: using (var scope = new TransactionScope()) { ToDo1(
我在服务器端代码 (WCF) 中使用 TransactionScope 类时遇到性能问题。 我的代码从客户端获取请求,创建 TransactionScope 并执行短操作(通常最多 100 毫秒)。
我正在处理一个几乎不存在事务的遗留项目,这会在出现错误时导致大量的部分提交。 SQL 调用混合了原始 ADO、Linq to Entities 和 EntityFramework,我想让它们在事务中运
我是一名优秀的程序员,十分优秀!