如果有人能指引我直截了当,非常感谢!!!
对任何重新开始道歉,我看过很多例子,但没有任何解决MVC模式的例子。
我的困境是 MVC Controller 的实现,它可以处理多个请求和Db操作,但在操作员完成必要的进程之前从不提交任何内容。
例如,使用生成的Id PrimaryKey添加新的父记录并返回记录信息。现在,运营商可以通过传递必需的ForiegnKey来添加子记录。其中一些儿童记录可能有自己的孩子等。在任何事情发生之前,操作员必须完成整个过程。
除非我完全离开,否则我无法理解这一点。我碰到了这些:
How to make a transaction in asp.net-core 2.0?
Alternative to TransactionScope of System.Transaction assembly in .net core framework
根据我的理解, System.Transactions 目前在.Net Core 2.0.x中可用。正如3568202所指出的那样:
https://docs.microsoft.com/en-us/dotnet/api/system.transactions.transactionscope?view=netcore-2.0
https://docs.microsoft.com/en-us/dotnet/framework/data/transactions/managing-concurrency-with-dependenttransaction 有一个WorkerThread示例我玩了一下。
但该示例并未准确显示 Transactions.Current 的来源。这是我在控制器中撞墙的地方。
我无法找出从 MyDbContext.Database.BeginTransaction()派生的 IDbContextTransaction 的转换;和 System.Transactions 的东西。
由于 IDbContextTransaction 创建的交易没有 .DependentClone()。
我错过了一些东西,一个界面?我不能把它放在一起......
然后我遇到了这个,看起来更直接:
与 TransactionScope 无关,第一行似乎是救赎:
“您还可以跨多个上下文实例共享事务。”
尝试在Controller中实现示例后,我不断得到可怕的:
“InvalidOperationException:指定的事务不是 与当前连接相关联。只有交易相关 可以使用当前连接。“
此外,最重要的是甚至,在我所有的阅读中,它似乎表明并不多,如果使用注入的上下文可以做到这一点??? !!!嗯,什么,为什么?
如何使用正确的“使用”模式???
我正在使用.Net Core 2.0.5和VS 2017 15.5.3
顺便说一句 - 我这里没有使用存储库,但如果解决方案需要存储库,那么我就是这个想法。
以下是我正在查看的基本设置
public class MyDbContext : DbContext
{
public MyDbContext(DbContextOptions<MyDbContext> options) : base(options)
{ }
public DbSet<Source> Sources { get; set; }
public DbSet<Comment> Comments { get; set; }
public DbSet<DwsFileInfo> DwsFileInfo { get; set; }
}
然后在 Startup.ConfigureServices
中services.AddDbContext<MyDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("MyConnection")));
然后是控制器:
public class MyController : Controller
{
private MyDbContext MyDbContext { get; set; }
private static IDbContextTransaction RootTransaction { get; set; }
//private DependentTransaction DependentTransaction { get; set; }
//private TransactionScope ScopedTransaction { get; set; }
public CommentsController(MyDbContext context)
{
MyDbContext = context;
if (RootTransaction == null)
{
RootTransaction = MyDbContext.Database.BeginTransaction();
}
else
{
MyDbContext.Database.UseTransaction(RootTransaction.GetDbTransaction());
}
}
/// <summary>
/// Not sure I really need this?!?
/// </summary>
~CommentsController()
{
if (RootTransaction != null && RootTransaction.GetDbTransaction() != null)
{
RootTransaction.Rollback();
}
RootTransaction.Dispose();
MyDbContext.Dispose();
}
public IActionResult Add(object recordinfo)
{
// DB operations
}
public IActionResult Add2(object recordinfo)
{
// DB operations
}
public IActionResult Edit(object recordinfo)
{
// Db Operations
}
/// <summary>
/// something here to manage, instead of in the constructor
/// or relying on the destructor??
/// </summary>
private void ManageTransaction()
{
//commit
//rollback
//dispose
}
}
我已经使用以下方法将一些特定于应用程序的信息注入上下文中:
app.Use(next => context =>
{
string path = context.Request.Path;
//modify context accordingly per path
return next(context);
});
但无法完全确定&#34;相应地修改&#34;意思是......现在我发现自己受到StackOverflow的支配...... 非常感谢每个人的时间和考虑。非常感谢!!!
答案 0 :(得分:2)
TL; DR :传奇模式可帮助您在没有环境/数据库相关事务的情况下解决问题。 Sagas也是交易,但以不同的方式,更像是状态机。
我的困境是 MVC Controller 的实现,它可以处理多个请求和Db操作,但在操作员完成必要的进程之前从不提交任何内容。
这是你的第一次误解。这就是网络和互联网的运作方式。 Http是无国籍的。您不能使用Http存储状态,并且单个请求所需的所有数据都应与请求本身一起发送。
或者您将设计更改为允许持久保存父记录,然后在后续请求中添加子对象。或者让您的客户将它们全部发送到一起:
Json示例:
{
// EF core assigns a new key when the key is null or has the default value
parentId: 0,
name: "Parent",
children: [{
name: "Child 1",
},{
name: "Child 2",
}]
}
现在,您可以在一个请求中拥有所有数据,并且可以在单个操作中处理它。在jQuery,Angular等年代,它不是问题。
其中一些儿童记录可能有自己的子女等。在任何事情发生之前,经营者必须完成整个过程。
您在考虑开发桌面应用程序时的想法。但是网络不是桌面应用程序,你不能通过http传输状态作为无状态协议。
您必须调整设计并使用更加网络友好的流程。或者只是创建一个桌面应用程序,如果这是一个绝对的要求;)
尝试在Controller中实现示例后,我不断得到可怕的:
“InvalidOperationException:指定的事务不是 与当前连接相关联。只有交易相关 可以使用当前连接。“
此外,最重要的是甚至,在我所有的阅读中,它似乎表明并不多,如果使用注入的上下文可以做到这一点??? !!!嗯,什么,为什么?
不是您想要的方式,而不是交易范围。 TransactionScope旨在执行多个数据库操作以保证一致性。这并不意味着数据何时会异步并在任何可能的时间延迟。
顺便说一句 - 我这里没有使用存储库,但如果解决方案需要存储库,那么我就是这个想法。
您正在使用存储库。 EntityFramework是Unit Of Work和Repository模式的实现。 DbContext是工作单元,而DbSet<T>
属性是存储库。
但人们通常倾向于将EF Core抽象出自己的存储库。
你想要它的方式不会起作用,因为DbContext必须是作用域的(或者你冒着内存泄漏的风险)。此外,DbContext不是线程安全的,因此它只能由单个线程安全使用。这就是为什么它默认为scoped,尝试从另一个线程访问它只会抛出一个无效的操作异常。
最后但并非最不重要的一点是,如果您有长时间运行的交易,其中数据可以按任何给定的顺序和任何给定时间进行,那么手头有一种模式。
它被称为流程经理/传奇。传奇或流程管理器是一个长期运行的过程。例如,现在可以发生一个操作,下一个操作可以在2分钟后发生。第三个甚至可能需要一个小时。
传奇的行为类似于状态机。它将接收一条消息(命令)来执行某个操作,然后将其保持状态(到数据库,内存,分布式缓存,会话,适合您的场景的任何内容)。
然后一些未定义的时间,第二个命令到来并对它执行一些操作。甚至后来第三个命令。只有当传奇处于特定状态时,它才能作为一个整体提交。
想象一下,你想去度假。现在您想预订航班和酒店。
现在,只有在您的酒店和航班确认后,您的假期才会被提交&#34;承诺&#34;。例如,如果酒店公司拒绝您的请求,您就无法去度假。然后,您可以发出另一个命令(寻找另一家酒店)或取消您的假期。取消假期后,您还需要取消航班。
这相当于交易中的回滚。
在一个传奇故事中,您只需删除已注册的记录或将&#34;度假故事&#34;在&#34;取消&#34;状态。