EF 6 DB-First系列--Entity Framework中的事务

Entity Framework中的事务

在这里您将了解EF 6 & EF Core中的事务。

在Entity Framework中,SaveChanges()方法在内部创建一个事务,并将所有的INSERT、UPDATE和DELETE操作包装在其中。多个SaveChanges()调用,创建单独的事务,执行CRUD操作,然后提交每个事务。下面的示例演示了这一点。

using (var context = new SchoolContext())
{
    context.Database.Log = Console.Write;

    var standard = context.Standards.Add(new Standard() { StandardName = "1st Grade" });

    context.Students.Add(new Student()
    {
        FirstName = "Rama",
        StandardId = standard.StandardId
    });

    context.SaveChanges();

	context.Courses.Add(new Course() { CourseName = "Computer Science" });

    context.SaveChanges();
}

上面的示例将向控制台显示以下输出。
在这里插入图片描述
在上面的示例中,我们将所有数据库命令记录到控制台。我们添加了一个新的Standard实体和Student实体,并使用SaveChanges()方法将它们保存到数据库中。这将创建一个新的事务,并在事务中为Standard和Student实体执行INSERT命令并提交它们。在此之后,我们添加一个新的Course实体并调用SaveChanges()。这将创建另一个事务,执行INSERT命令,然后提交事务。因此,每个SaveChanges()方法调用都会创建一个新的事务,并在其中执行数据库命令。

在单个事务中进行多个savechange

EF 6和EF Core允许我们使用以下方法创建或使用多个SaveChanges()调用单个事务:

  1. DbContext.Database.BeginTransaction(): 为底层数据库创建一个新的事务,并允许我们使用多个SaveChanges方法调用提交或回滚对数据库所做的更改。
  2. DbContext.Database.UseTransaction(): 允许我们传递在上下文对象范围之外创建的现有事务对象。这将允许EF在外部事务对象中执行命令。或者,传入null来清除框架对该事务的了解。

DbContext.Database.BeginTransaction()

下面的例子演示了使用BeginTransaction()创建一个新的事务对象,然后使用多个SaveChanges()调用。

using (var context = new SchoolContext())
{
    context.Database.Log = Console.Write;

    using (DbContextTransaction transaction = context.Database.BeginTransaction()) //开启事务
    {
        try
        {
            var standard = context.Standards.Add(new Standard() { StandardName = "1st Grade" });

            context.Students.Add(new Student()
            {
                FirstName = "Rama2",
                StandardId = standard.StandardId
            });
            context.SaveChanges();

            context.Courses.Add(new Course() { CourseName = "Computer Science" });
            context.SaveChanges();

            transaction.Commit(); //提交事务
        }
        catch (Exception ex)
        {
            transaction.Rollback(); //事务回滚
            Console.WriteLine("Error occurred.");
        }
    }
}

在上面的例子中,我们创建了新的Standard、Student和Course实体,并通过调用两个SaveChanges()将它们保存到数据库中,这两个SaveChanges()在一个事务中执行INSERT命令。下图显示了输出日志。

在这里插入图片描述
注意:你可以在DbContext.Database.BeginTransaction()方法中指定不同的隔离级别。访问MSDN可了解有关隔离级别(https://msdn.microsoft.com/en-us/library/system.data.isolationlevel(v=vs.113).aspx)的更多信息。

如果发生异常,则对数据库所做的所有更改都将回滚。

using (var context = new SchoolContext())
{
    context.Database.Log = Console.Write;

    using (DbContextTransaction transaction = context.Database.BeginTransaction())
    {
        try
        {
            var standard = context.Standards.Add(new Standard() { StandardName = "1st Grade" });

            context.Students.Add(new Student()
            {
                FirstName = "Rama",
                StandardId = standard.StandardId
            });
            context.SaveChanges();
            // throw exectiopn to test roll back transaction
            throw new Exception();

            context.Courses.Add(new Course() { CourseName = "Computer Science" });
            context.SaveChanges();

            transaction.Commit();
        }
        catch (Exception ex)
        {
            transaction.Rollback();
            Console.WriteLine("Error occurred.");
        }
    }
}

在上面的例子中,我们在第一次SaveChanges()调用之后抛出一个异常。这将执行一个catch块,在其中调用RollBack()方法来回滚对数据库所做的任何更改。输出结果如下图所示。

在这里插入图片描述

DbContext.Database.UseTransaction()

DbContext.Database.UseTransaction()方法允许我们使用在上下文对象范围之外创建的现有事务。如果使用UseTransaction()方法,则上下文将不会创建内部事务对象,而是使用提供的事务。

下面的示例演示了使用EF 6 code-first的UseTransaction()方法。

private static void Main(string[] args)
{
    string providerName = "System.Data.SqlClient";
    string serverName = ".";
    string databaseName = "SchoolDB";

    // Initialize the connection string builder for the SQL Server provider.
    SqlConnectionStringBuilder sqlBuilder =
        new SqlConnectionStringBuilder();

    // Set the properties for the data source.
    sqlBuilder.DataSource = serverName;
    sqlBuilder.InitialCatalog = databaseName;
    sqlBuilder.IntegratedSecurity = true;

    using (SqlConnection con = new SqlConnection(sqlBuilder.ToString()))
    {
        con.Open();
        using (SqlTransaction transaction = con.BeginTransaction())
        {
            try
            {
                using (SchoolContext context = new SchoolContext(con, false))
                {
                    context.Database.UseTransaction(transaction);

                    context.Students.Add(new Student() { Name = "Ravi" });
                    context.SaveChanges();
                }

                using (SchoolContext context = new SchoolContext(con, false))
                {
                    context.Database.UseTransaction(transaction);

                    context.Grades.Add(new Standard() { GradeName = "Grade 1", Section = "A" });
                    context.SaveChanges();
                }
                transaction.Commit();
            }
            catch (Exception ex)
            {
                transaction.Rollback();

                Console.WriteLine(ex.InnerException);
            }
        }
    }
}

下面是上面例子中使用的一个SchoolContext类。

public class SchoolContext : DbContext
{
    public SchoolContext(DbConnection con, bool contextOwnsConnection) :base(con, contextOwnsConnection)
    {

    }
    public SchoolContext(): base("SchoolDB")
    {
        Database.SetInitializer<SchoolContext>(new CreateDatabaseIfNotExists<SchoolContext>());
    }

    public DbSet<Student> Students { get; set; }
    public DbSet<Standard> Grades { get; set; }
    public DbSet<Course> Courses { get; set; }
}

参考

https://www.entityframeworktutorial.net/
https://msdn.microsoft.com/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值