(26)ASP.NET Core EF保存(基本保存、保存相关数据、级联删除、使用事务)

1.简介

每一个上下文实例都有一个ChangeTracker,它负责跟踪须要写入数据库的更改。更改实体类的实例时,这些更改会记录在ChangeTracker中,而后在调用SaveChanges时会被写入数据库中。此数据库提供程序负责将更改转换为特定于数据库的操做(例如,关系数据库的INSERT、UPDATE和DELETE命令)。数据库

2.基本保存

了解如何使用上下文和实体类添加、修改和删除数据。post

2.1添加数据

使用DbSet.Add方法添加实体类的新实例。调用SaveChanges时,数据将插入到数据库中。spa

using (var context = new BloggingContext())
{
    var blog = new Blog { Url = "http://sample.com" };
    context.Blogs.Add(blog);
    context.SaveChanges();
}

2.2更新数据

EF将自动检测对由上下文跟踪的现有实体所作的更改。这包括从数据库加载查询的实体,以及以前添加并保存到数据库的实体。只需经过赋值来修改属性,而后调用SaveChanges便可。code

using (var context = new BloggingContext())
{
    var blog = context.Blogs.First();
    blog.Url = "http://sample.com/blog";
    context.SaveChanges();
}

2.3删除数据

使用DbSet.Remove方法删除实体类的实例。若是实体已存在于数据库中,则将在SaveChanges期间删除该实体。若是实体还没有保存到数据库(即跟踪为“已添加”),则在调用SaveChanges时,该实体会从上下文中移除且再也不插入。blog

using (var context = new BloggingContext())
{
    var blog = context.Blogs.First();
    context.Blogs.Remove(blog);
    context.SaveChanges();
}

2.4单个SaveChanges中的多个操做

能够将多个添加/更新/删除操做合并到对SaveChanges的单个调用。事务

using (var context = new BloggingContext())
{
    // add
    context.Blogs.Add(new Blog { Url = "http://sample.com/blog_one" });
    context.Blogs.Add(new Blog { Url = "http://sample.com/blog_two" });
    // update
    var firstBlog = context.Blogs.First();
    firstBlog.Url = "";
    // remove
    var lastBlog = context.Blogs.Last();
    context.Blogs.Remove(lastBlog);
    context.SaveChanges();
}

3.保存关联数据

除了独立实体之外,还能够使用模型中定义的关系。rem

3.1添加关联数据

若是建立多个新的相关实体,则将其中一个添加到上下文时也会添加其余实体。在下面的示例中,博客和三个相关文章会所有插入到数据库中。找到并添加这些文章,由于它们能够经过Blog.Posts导航属性访问。get

using (var context = new BloggingContext())
{
    var blog = new Blog
    {
        Url = "http://blogs.msdn.com/dotnet",
        Posts = new List<Post>
        {
            new Post { Title = "Intro to C#" },
            new Post { Title = "Intro to VB.NET" },
            new Post { Title = "Intro to F#" }
        }
    };
    context.Blogs.Add(blog);
    context.SaveChanges();
}

3.2添加相关实体

若是从已由上下文跟踪的实体的导航属性中引用新实体,则将发现该实体并将其插入到数据库中。在下面的示例中,插入post实体,由于该实体会添加到已从数据库中提取的blog实体的Posts属性。博客

using (var context = new BloggingContext())
{
    var blog = context.Blogs.Include(b => b.Posts).First();
    var post = new Post { Title = "Intro to EF Core" };
    blog.Posts.Add(post);
    context.SaveChanges();
}

3.3更改关系

若是更改实体的导航属性,则将对数据库中的外键列进行相应的更改。在下面的示例中,post实体更新为属于新的blog实体,由于其Blog导航属性设置为指向blog,blog也会插入到数据库中,由于它是已由上下文post跟踪的实体的导航属性引用的新实体。it

using (var context = new BloggingContext())
{
    //新增一个主体实体
    var blog = new Blog { Url = "http://blogs.msdn.com/visualstudio" };
    var post = context.Posts.First();
    //post更新关系
    post.Blog = blog;
    context.SaveChanges();
}

4.级联删除

删除行为在DeleteBehavior枚举器类型中定义,而且能够传递到OnDelete Fluent API来控制:
●能够删除子项/依赖项
●子项的外键值能够设置为null
●子项保持不变
示例:

var blog = context.Blogs.Include(b => b.Posts).First();
var posts = blog.Posts.ToList();
DumpEntities("  After loading entities:", context, blog, posts);
context.Remove(blog);
DumpEntities($"  After deleting blog '{blog.BlogId}':", context, blog, posts);
try
{
    Console.WriteLine();
    Console.WriteLine("  Saving changes:");
    context.SaveChanges();
    DumpSql();
    DumpEntities("  After SaveChanges:", context, blog, posts);
}
catch (Exception e)
{
    DumpSql();
    Console.WriteLine();
    Console.WriteLine($"  SaveChanges threw {e.GetType().Name}: {(e is DbUpdateException ? e.InnerException.Message : e.Message)}");
}

记录结果:

 After loading entities:
    Blog '1' is in state Unchanged with 2 posts referenced.
      Post '1' is in state Unchanged with FK '1' and reference to blog '1'.
      Post '2' is in state Unchanged with FK '1' and reference to blog '1'.

  After deleting blog '1':
    Blog '1' is in state Deleted with 2 posts referenced.
      Post '1' is in state Unchanged with FK '1' and reference to blog '1'.
      Post '2' is in state Unchanged with FK '1' and reference to blog '1'.

  Saving changes:
    DELETE FROM [Posts] WHERE [PostId] = 1
    DELETE FROM [Posts] WHERE [PostId] = 2
    DELETE FROM [Blogs] WHERE [BlogId] = 1

  After SaveChanges:
    Blog '1' is in state Detached with 2 posts referenced.
      Post '1' is in state Detached with FK '1' and no reference to a blog.
      Post '2' is in state Detached with FK '1' and no reference to a blog.

5.事务

事务容许以原子方式处理多个数据库操做。若是已提交事务,则全部操做都会成功应用到数据库。若是已回滚事务,则全部操做都不会应用到数据库。

5.1控制事务

能够使用DbContext.Database API开始、提交和回滚事务。如下示例显示了两个SaveChanges()操做以及正在单个事务中执行的LINQ查询。并不是全部数据库提供应用程序都支持事务的。 调用事务API时,某些提供应用程序可能会引起异常或不执行任何操做。

using (var context = new BloggingContext())
{
    using (var transaction = context.Database.BeginTransaction())
    {
        try
        {
            context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" });
            context.SaveChanges();
            context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/visualstudio" });
            context.SaveChanges();
            var blogs = context.Blogs
                .OrderBy(b => b.Url)
                .ToList();
            // Commit transaction if all commands succeed, transaction will auto-rollback
            // when disposed if either commands fails
            transaction.Commit();
        }
        catch (Exception)
        {
            // TODO: Handle failure
        }
    }
}

6.总结

因为工做繁忙缘由,EF系列在这里也就完结了,暂时没有太多时间记录下去了。今天这个章节也偷了个懒,稍微精简一点,具体官方说明,我会在下面贴上的,请见谅。

参考文献:
基本保存
保存相关数据
级联删除
使用事务

相关文章
相关标签/搜索