EntityFramework Core笔记:保存数据(4)
1. 基本保存
每个DBContext实例都有一个ChangeTracker,负责跟踪需要写入数据库的更改。当实例发生更改时,更改会被记录在ChangeTracker中,在调用 SaveChanges
时被写入数据库。
1.1 添加数据
使用 DbSet.Add()添加实体类的新实例。 调用 SaveChanges() 时,数据将插入到数据库中。
using (var context = new LibingContext()) { var role = new Role { RoleName = "教师" }; context.Roles.Add(role); context.SaveChanges(); }
1.2 更新数据
Entity Framwork Core将自动检测对由DbContext跟踪的实体所做的更改。
更新数据:修改属性值,调用 SaveChanges()。
using (var context = new LibingContext()) { var role = context.Roles.Find(1); role.RoleName = "教师"; context.SaveChanges(); }
1.3 删除数据
使用 DbSet.Remove() 删除实体类的实例。
如果实体已存在于数据库中,则 SaveChanges() 将删除该实体。 如果实体尚未保存到数据库(即跟踪为“已添加”),则 SaveChanges() 时,该实体会从上下文中删除且不再插入。
using (var context = new LibingContext()) { var role = context.Roles.Find(1); context.Roles.Remove(role); context.SaveChanges(); }
1.4 一个SaveChanges 中的多个操作
可以将多个添加/更新/删除操作合并到对“SaveChanges”的单个调用。
对于大多数数据库提供程序,“SaveChanges”是事务性的。
using (var context = new LibingContext()) { // 新增 context.Roles.Add(new Role { RoleName = "管理员" }); context.Roles.Add(new Role { RoleName = "学生" }); // 修改 var modifyRole = context.Roles.Find(1); modifyRole.RoleName = "教师"; // 删除 var deleteRole = context.Roles.Where(t => t.RoleID == 2).FirstOrDefault(); context.Roles.Remove(deleteRole); context.SaveChanges(); }
2. 关联数据
2.1 添加新实体的关系图
using (var context = new LibingContext()) { var category = new Category { CategoryName = "手机", Products = new List<Product> { new Product { ProductName = "华为", UnitPrice = 2000 }, new Product { ProductName = "小米", UnitPrice = 1000 } } }; context.Categories.Add(category); context.SaveChanges(); }
exec sp_executesql N'SET NOCOUNT ON; INSERT INTO [Category] ([CategoryName]) VALUES (@p0); SELECT [CategoryID] FROM [Category] WHERE @@ROWCOUNT = 1 AND [CategoryID] = scope_identity(); ',N'@p0 nvarchar(4000)',@p0=N'手机'
exec sp_executesql N'SET NOCOUNT ON; INSERT INTO [Product] ([CategoryID], [ProductName], [UnitPrice]) VALUES (@p0, @p1, @p2); SELECT [ProductID] FROM [Product] WHERE @@ROWCOUNT = 1 AND [ProductID] = scope_identity(); ',N'@p0 int,@p1 nvarchar(4000),@p2 decimal(4,0)',@p0=1,@p1=N'华为',@p2=2000
exec sp_executesql N'SET NOCOUNT ON; INSERT INTO [Product] ([CategoryID], [ProductName], [UnitPrice]) VALUES (@p0, @p1, @p2); SELECT [ProductID] FROM [Product] WHERE @@ROWCOUNT = 1 AND [ProductID] = scope_identity(); ',N'@p0 int,@p1 nvarchar(4000),@p2 decimal(4,0)',@p0=1,@p1=N'小米',@p2=1000
2.2 添加关联实体
如果从已由DbContext跟踪的实体的导航属性中引用新实体,则该实体将插入到数据库中。
using Microsoft.EntityFrameworkCore;
using (var context = new LibingContext()) { var category = context.Categories .Include(t => t.Products) .Where(t => t.CategoryID == 1) .FirstOrDefault(); category.Products.Add(new Product { ProductName = "VIVO", UnitPrice = 1500 }); context.SaveChanges(); }
SELECT TOP(1) [t].[CategoryID], [t].[CategoryName] FROM [Category] AS [t] WHERE [t].[CategoryID] = 1 ORDER BY [t].[CategoryID]
SELECT [t.Products].[ProductID], [t.Products].[CategoryID], [t.Products].[ProductName], [t.Products].[UnitPrice] FROM [Product] AS [t.Products] INNER JOIN ( SELECT TOP(1) [t0].[CategoryID] FROM [Category] AS [t0] WHERE [t0].[CategoryID] = 1 ORDER BY [t0].[CategoryID] ) AS [t1] ON [t.Products].[CategoryID] = [t1].[CategoryID] ORDER BY [t1].[CategoryID]
exec sp_executesql N'SET NOCOUNT ON; INSERT INTO [Product] ([CategoryID], [ProductName], [UnitPrice]) VALUES (@p0, @p1, @p2); SELECT [ProductID] FROM [Product] WHERE @@ROWCOUNT = 1 AND [ProductID] = scope_identity(); ',N'@p0 int,@p1 nvarchar(4000),@p2 decimal(4,0)',@p0=1,@p1=N'VIVO',@p2=1500
2.3 更改关系
如果更改实体的导航属性,则将对数据库中的外键列进行相应的更改。
using (var context = new LibingContext()) { var category = context.Categories.Find(2); var product = context.Products.Find(1); product.Category = category; context.SaveChanges(); }
exec sp_executesql N'SELECT TOP(1) [e].[CategoryID], [e].[CategoryName] FROM [Category] AS [e] WHERE [e].[CategoryID] = @__get_Item_0',N'@__get_Item_0 int',@__get_Item_0=2
exec sp_executesql N'SELECT TOP(1) [e].[ProductID], [e].[CategoryID], [e].[ProductName], [e].[UnitPrice] FROM [Product] AS [e] WHERE [e].[ProductID] = @__get_Item_0',N'@__get_Item_0 int',@__get_Item_0=1
exec sp_executesql N'SET NOCOUNT ON; UPDATE [Product] SET [CategoryID] = @p0 WHERE [ProductID] = @p1; SELECT @@ROWCOUNT; ',N'@p1 int,@p0 int',@p1=1,@p0=2
2.4 删除关系
可以通过将引用导航设置为 null 或从集合导航中删除相关实体来删除关系。
默认情况下,对于必选关系,将配置级联删除行为,并将从数据库中删除子实体/依赖实体。 对于可选关系,默认情况下不会配置级联删除,但会将外键属性设置为 null。
using (var context = new LibingContext()) { var category = context.Categories .Include(t => t.Products) .Where(t => t.CategoryID == 1) .FirstOrDefault(); //category.Products.Remove(category.Products.FirstOrDefault()); category.Products = null; context.SaveChanges(); }
SELECT TOP(1) [t].[CategoryID], [t].[CategoryName] FROM [Category] AS [t] WHERE [t].[CategoryID] = 1 ORDER BY [t].[CategoryID]
SELECT [t.Products].[ProductID], [t.Products].[CategoryID], [t.Products].[ProductName], [t.Products].[UnitPrice] FROM [Product] AS [t.Products] INNER JOIN ( SELECT TOP(1) [t0].[CategoryID] FROM [Category] AS [t0] WHERE [t0].[CategoryID] = 1 ORDER BY [t0].[CategoryID] ) AS [t1] ON [t.Products].[CategoryID] = [t1].[CategoryID] ORDER BY [t1].[CategoryID]
exec sp_executesql N'SET NOCOUNT ON; DELETE FROM [Product] WHERE [ProductID] = @p0; SELECT @@ROWCOUNT; ',N'@p0 int',@p0=2
exec sp_executesql N'SET NOCOUNT ON; DELETE FROM [Product] WHERE [ProductID] = @p0; SELECT @@ROWCOUNT; ',N'@p0 int',@p0=3