前面在介绍ADO.NET时,介绍了使用事务编程的内容。每次使用Entity Framework访问数据库时,都涉及事务。可以隐式地使用事务或根据需要使用配置显示地创建它们。此节使用的示例项目以两种方式展示事务。这里,Menu、MenuCard和MenuContext类的用法与前面的MenusSample项目相同。
1. 使用隐式的事务
SaveChanges方法的调用会自动解析为一个事务。如果需要进行的一部分变更失败,例如,因为数据库约束,就回滚所有已经完成的更改。下面的代码片段演示了这一点。其中,第一个Menu(m1)用有效的数据创建。对现有MenuCard的引用是通过提供MenuCardId完成的。更新成功后,Menu(m1)的MenuCard属性自动填充。然而,所创建的第二个菜单mInvalid,因为提供的MenuCardId高于数据库中可用的最高ID,所以引用了无效的菜单卡。因为MenuCard和Menu之间定义了外键关系,所以添加这个对象会失败:
private static async Task AddTwoRecordsWithOneTx()
{
Console.WriteLine(nameof(AddTwoRecordsWithOneTx));
try
{
using (var context = new MenusContext())
{
var card = await context.MenuCards.FirstAsync();
var m1 = new Menu()
{
MenuCardId = card.MenuCardId,
Text = "added",
Price = 99.99m,
};
int hightestCardId = await context.MenuCards.MaxAsync(c => c.MenuCardId);
var mInvalid = new Menu()
{
MenuCardId = ++hightestCardId,
Text = "invalid",
Price = 999.99m
};
await context.Menus.AddRangeAsync(m1