EFCore入门 实战教程

Entity Framework Core (EF Core) 是一个轻量级、可扩展且跨平台的 ORM(对象关系映射)框架,用于 .NET 应用程序中进行数据访问。本文将带您从零开始,通过实际操作步骤和 VS2022 截图,深入了解 EF Core 的各种用法,包括模型创建、数据查询、数据修改、迁移、高级查询等。

环境准备

在开始之前,请确保您已安装以下软件:

  • Visual Studio 2022:建议安装最新版本,并确保已安装 .NET 开发工具。
  • .NET SDK:确保已安装 .NET 6 或更高版本。
  • 数据库:本文将使用 SQL Server 作为示例,您也可以使用其他数据库,如 MySQL、PostgreSQL 等。

创建项目

  1. 打开 Visual Studio 2022,点击“创建新项目”。

    创建新项目

  2. 选择 “控制台应用程序”,点击“下一步”。

    选择控制台应用程序

  3. 输入项目名称(例如“EFCoreDemo”),并选择项目位置,点击“下一步”。

    配置新项目

  4. 选择 “.NET 6.0” 或更高版本,点击“创建”。

    选择 .NET 版本

安装 EF Core 相关 NuGet 包

  1. 在 Visual Studio 2022 中,右键点击项目名称(“EFCoreDemo”),选择 “管理 NuGet 程序包”。

    管理 NuGet 程序包

  2. 在 “浏览” 选项卡中,搜索并安装以下 NuGet 包:

    • Microsoft.EntityFrameworkCore
    • Microsoft.EntityFrameworkCore.SqlServer (如果您使用 SQL Server)
    • Microsoft.EntityFrameworkCore.Tools

    安装 NuGet 包

    请确保安装的版本与您的 .NET SDK 版本兼容。

创建实体类

实体类代表数据库中的表。在项目中创建一个新的文件夹 “Models”,并在其中创建以下两个类:

  1. Blog.cs

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    namespace EFCoreDemo.Models
    {
    public class Blog
    {
    public int Id { get; set; }
    public string Title { get; set; }
    public string Author { get; set; }
    public List<Post> Posts { get; set; }
    }
    }
  2. Post.cs

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    namespace EFCoreDemo.Models
    {
    public class Post
    {
    public int Id { get; set; }
    public string Content { get; set; }
    public int BlogId { get; set; }
    public Blog Blog { get; set; }
    }
    }

创建数据库上下文

数据库上下文是 EF Core 的核心,它代表与数据库的会话。创建一个新的类 AppDbContext.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
using EFCoreDemo.Models;
using Microsoft.EntityFrameworkCore;

namespace EFCoreDemo
{
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}

public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
}
}

配置数据库连接

在 Program.cs 文件中配置数据库连接:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using EFCoreDemo;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var builder = Host.CreateDefaultBuilder(args);

builder.ConfigureServices((hostContext, services) =>
{
services.AddDbContext<AppDbContext>(options =>
{
options.UseSqlServer("Data Source=.;Initial Catalog=EFCoreDemoDB;Integrated Security=True;TrustServerCertificate=True;");
});
});

var host = builder.Build();
// 确保数据库存在
using (var scope = host.Services.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
dbContext.Database.EnsureCreated(); // 确保数据库已创建
}

host.Run();

注意: 请将 Data Source, Initial Catalog 修改为您实际的 SQL Server 连接字符串。

创建迁移

迁移允许您将数据库架构与实体类保持同步。

打开 “程序包管理器控制台” (在 VS2022 中,选择 “视图” -> “其他窗口” -> “程序包管理器控制台”)。
打开程序包管理器控制台
运行以下命令:

1
Add-Migration InitialCreate

这将创建一个新的迁移文件,其中包含创建数据库架构的必要代码。

运行以下命令:

1
Update-Database

这将将迁移应用到数据库,创建表。

添加数据

在 Program.cs 文件中添加以下代码,插入一些示例数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
using EFCoreDemo;
using EFCoreDemo.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var builder = Host.CreateDefaultBuilder(args);

builder.ConfigureServices((hostContext, services) =>
{
services.AddDbContext<AppDbContext>(options =>
{
options.UseSqlServer("Data Source=.;Initial Catalog=EFCoreDemoDB;Integrated Security=True;TrustServerCertificate=True;");
});
});

var host = builder.Build();
// 确保数据库存在
using (var scope = host.Services.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
dbContext.Database.EnsureCreated(); // 确保数据库已创建

// 添加示例数据
if (!dbContext.Blogs.Any())
{
var blog = new Blog { Title = "My First Blog", Author = "John Doe" };
var post1 = new Post { Content = "This is my first post", Blog = blog };
var post2 = new Post { Content = "This is my second post", Blog = blog };
dbContext.Blogs.Add(blog);
dbContext.Posts.AddRange(post1, post2);
dbContext.SaveChanges();
}
}

host.Run();

查询数据

在 Program.cs 中添加以下代码,查询并显示数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
using EFCoreDemo;
using EFCoreDemo.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var builder = Host.CreateDefaultBuilder(args);

builder.ConfigureServices((hostContext, services) =>
{
services.AddDbContext<AppDbContext>(options =>
{
options.UseSqlServer("Data Source=.;Initial Catalog=EFCoreDemoDB;Integrated Security=True;TrustServerCertificate=True;");
});
});

var host = builder.Build();
// 确保数据库存在
using (var scope = host.Services.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
dbContext.Database.EnsureCreated(); // 确保数据库已创建

// 添加示例数据
if (!dbContext.Blogs.Any())
{
var blog = new Blog { Title = "My First Blog", Author = "John Doe" };
var post1 = new Post { Content = "This is my first post", Blog = blog };
var post2 = new Post { Content = "This is my second post", Blog = blog };
dbContext.Blogs.Add(blog);
dbContext.Posts.AddRange(post1, post2);
dbContext.SaveChanges();
}

// 查询数据
var blogs = dbContext.Blogs.Include(b => b.Posts).ToList();
foreach (var blog in blogs)
{
Console.WriteLine($"Blog: {blog.Title} by {blog.Author}");
foreach (var post in blog.Posts)
{
Console.WriteLine($" - Post: {post.Content}");
}
}
}

host.Run();

这段代码使用 Include 方法加载了 Blog 实体及其关联的 Posts 实体,然后遍历并打印了结果。

修改数据

在 Program.cs 中添加以下代码,修改现有数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
using EFCoreDemo;
using EFCoreDemo.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var builder = Host.CreateDefaultBuilder(args);

builder.ConfigureServices((hostContext, services) =>
{
services.AddDbContext<AppDbContext>(options =>
{
options.UseSqlServer("Data Source=.;Initial Catalog=EFCoreDemoDB;Integrated Security=True;TrustServerCertificate=True;");
});
});

var host = builder.Build();
// 确保数据库存在
using (var scope = host.Services.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
dbContext.Database.EnsureCreated(); // 确保数据库已创建

// 添加示例数据
if (!dbContext.Blogs.Any())
{
var blog = new Blog { Title = "My First Blog", Author = "John Doe" };
var post1 = new Post { Content = "This is my first post", Blog = blog };
var post2 = new Post { Content = "This is my second post", Blog = blog };
dbContext.Blogs.Add(blog);
dbContext.Posts.AddRange(post1, post2);
dbContext.SaveChanges();
}

// 查询数据
var blogs = dbContext.Blogs.Include(b => b.Posts).ToList();
foreach (var blog in blogs)
{
Console.WriteLine($"Blog: {blog.Title} by {blog.Author}");
foreach (var post in blog.Posts)
{
Console.WriteLine($" - Post: {post.Content}");
}
}

// 修改数据
var blogToUpdate = dbContext.Blogs.FirstOrDefault();
if (blogToUpdate != null)
{
blogToUpdate.Title = "My Updated Blog Title";
dbContext.SaveChanges();
Console.WriteLine("Blog updated successfully.");
}
}

host.Run();

这段代码首先查询第一个 Blog 实体,然后更新其 Title 属性,最后调用 SaveChanges 方法将更改保存到数据库。

删除数据

在 Program.cs 中添加以下代码,删除数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
using EFCoreDemo;
using EFCoreDemo.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var builder = Host.CreateDefaultBuilder(args);

builder.ConfigureServices((hostContext, services) =>
{
services.AddDbContext<AppDbContext>(options =>
{
options.UseSqlServer("Data Source=.;Initial Catalog=EFCoreDemoDB;Integrated Security=True;TrustServerCertificate=True;");
});
});

var host = builder.Build();
// 确保数据库存在
using (var scope = host.Services.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
dbContext.Database.EnsureCreated(); // 确保数据库已创建

// 添加示例数据
if (!dbContext.Blogs.Any())
{
var blog = new Blog { Title = "My First Blog", Author = "John Doe" };
var post1 = new Post { Content = "This is my first post", Blog = blog };
var post2 = new Post { Content = "This is my second post", Blog = blog };
dbContext.Blogs.Add(blog);
dbContext.Posts.AddRange(post1, post2);
dbContext.SaveChanges();
}

// 查询数据
var blogs = dbContext.Blogs.Include(b => b.Posts).ToList();
foreach (var blog in blogs)
{
Console.WriteLine($"Blog: {blog.Title} by {blog.Author}");
foreach (var post in blog.Posts)
{
Console.WriteLine($" - Post: {post.Content}");
}
}

// 修改数据
var blogToUpdate = dbContext.Blogs.FirstOrDefault();
if (blogToUpdate != null)
{
blogToUpdate.Title = "My Updated Blog Title";
dbContext.SaveChanges();
Console.WriteLine("Blog updated successfully.");
}

// 删除数据
var blogToDelete = dbContext.Blogs.FirstOrDefault();
if (blogToDelete != null)
{
dbContext.Blogs.Remove(blogToDelete);
dbContext.SaveChanges();
Console.WriteLine("Blog deleted successfully.");
}
}

host.Run();

这段代码首先查询第一个 Blog 实体,然后使用 Remove 方法将其删除,最后调用 SaveChanges 方法将更改保存到数据库。

高级查询技巧

EF Core 提供了多种高级查询技巧,例如:

Where 子句:用于过滤数据。
OrderBy 和 OrderByDescending:用于排序数据。
Skip 和 Take:用于分页。
Select:用于选择特定的列。
GroupBy:用于分组。
Join:用于连接多个表。

以下是一个示例,展示如何使用 Where 和 OrderBy:

1
2
3
4
5
6
7
8
9
10
11
// 高级查询
var filteredBlogs = dbContext.Blogs
.Where(b => b.Author.Contains("John"))
.OrderByDescending(b => b.Title)
.ToList();

Console.WriteLine("\nFiltered and Sorted Blogs:");
foreach (var blog in filteredBlogs)
{
Console.WriteLine($" - Blog: {blog.Title} by {blog.Author}");
}

总结

通过本文,您已经掌握了 EF Core 的基本用法,包括:

创建实体类和数据库上下文。
配置数据库连接。
创建迁移并更新数据库。
添加、查询、修改和删除数据。
使用高级查询技巧。

EF Core 是一个功能强大的 ORM 框架,可以帮助您更高效地进行数据访问。建议您继续深入学习 EF Core 的更多功能,例如:

关系映射:一对一、一对多、多对多关系。
配置:使用 Fluent API 或数据注释进行配置。
性能优化:使用索引、延迟加载等。
事务:处理数据库事务。