您了解了如何在连接的方案中保存数据。在这里,您将学习如何在无连接的场景中保存数据。
在无连接的方案中保存数据与连接方案中的数据略有不同。在无连接的方案中,DbContext
不知道无连接的实体,因为实体是在当前DbContext
实例的范围之外添加或修改的。因此,您需要将无连接的实体附加到适当的上下文,EntityState
以便对数据库执行CUD(创建,更新,删除)操作。
下图说明了无连接方案中的CUD操作:
根据上图,未被其跟踪的实体DbContext
需要附加到DbContext
适当的实体EntityState
。例如,为新实体添加状态,已编辑实体的已修改状态和已删除实体的已删除状态,这将在SaveChanges()
调用方法时在数据库中生成INSERT,UPDATE或DELETE命令。
必须执行以下步骤,以便在断开连接的方案中使用Entity Framework Core将记录插入,更新或删除到DB表中:
- 将实体附加到
DbContext
适当的EntityState
例如添加,修改或删除 - 通话
SaveChanges()
方式
以下示例演示如何使用上述步骤将新记录插入数据库:
//Disconnected entity
var std = new Student(){ Name = "Bill" };
using (var context = new SchoolContext())
{
//1. Attach an entity to context with Added EntityState
context.Add<Student>(std);
//or the followings are also valid
// context.Students.Add(std);
// context.Entry<Student>(std).State = EntityState.Added;
// context.Attach<Student>(std);
//2. Calling SaveChanges to insert a new record into Students table
context.SaveChanges();
}
在上面的示例中,std
是Student
实体的无连接的实例。该context.Add<Student>()
方法将Student
实体附加到具有已添加状态的上下文。该SaveChanges()
方法构建并执行以下INSERT语句:
exec sp_executesql N'SET NOCOUNT ON;
INSERT INTO [Students] ([Name])
VALUES (@p0);
SELECT [StudentId]
FROM [Students]
WHERE @@ROWCOUNT = 1 AND [StudentId] = scope_identity();',N'@p0 nvarchar(4000),
@p1 nvarchar(4000) ',@p0=N'Bill'
go
EF Core提供了多种添加添加状态实体的方法。在上面的例子中,context.Students.Add(std);
,context.Entry<Student>(std).State = EntityState.Added;
并context.Attach<Student>(std);
会导致相同的INSERT语句如上。
实体框架核心提供以下方法DbContext
和DbSet
方法,将已断开连接的实体与Added相连EntityState
,而后者又将在数据库中执行INSERT语句。
DbContext方法 | DbSet方法 | 描述 |
---|---|---|
DbContext.Attach | DbSet.Attach | 将实体附加到DbContext。为Key属性具有值的实体设置Unchanged状态,为Key属性为空的实体或数据类型的默认值设置Added状态。 |
DbContext.Add | DbSet.Add | 将实体附加到具有已添加状态的DbContext。 |
DbContext.AddRange | DbSet.AddRange | 将实体集合附加到具有已添加状态的DbContext。 |
DbContext.Entry | – | 获取EntityEntry 指定实体,该实体提供对更改跟踪信息和操作的访问权限。 |
DbContext.AddAsync | DbSet.AddAsync | 将实体附加到具有已添加状态的DbContext的异步方法,如果没有则开始跟踪它。调用SaveChangesAsync()时,数据将插入数据库。 |
DbContext.AddRangeAsync | DbSet.AddRangeAsync | 将多个实体附加到具有添加状态的DbContext的异步方法,如果没有,则开始跟踪它们。调用SaveChangesAsync()时,数据将插入数据库。 |
注意:上述DbContext
方法是在EF Core中引入的(它们在EF 6或之前版本中不可用)。两者DbContext
和DbSet
方法执行相同的操作。您使用哪一个取决于您的编码模式和偏好。
插入关系数据
在上一章中,我们学会了在两个实体之间创建一对一,一对多和多对多的关系。实体框架API插入相关实体中包含的所有关系数据。
使用DbContext.Add
or DbSet.Add
方法将相关实体添加到数据库。该Add
方法将实体附加到上下文,并将已添加状态设置为实体图中的所有实体,其Id(Key)属性为空,null或数据类型的默认值。请考虑以下示例。
var stdAddress = new StudentAddress()
{
City = "SFO",
State = "CA",
Country = "USA"
};
var std = new Student()
{
Name = "Steve",
Address = stdAddress
};
using (var context = new SchoolContext())
{
// Attach an entity to DbContext with Added state
context.Add<Student>(std);
// Calling SaveChanges to insert a new record into Students table
context.SaveChanges();
}
在上面的示例中,context.Add<Student>(std)
添加了一个Student
实体实例。EF Core API StudentAddress
通过引用导航属性Student
和EntityState
两个要添加的实体的标记到达实例,这将构建并执行以下两个INSERT命令SaveChanges()
。
exec sp_executesql N'SET NOCOUNT ON;
INSERT INTO [Students] ([Name])
VALUES (@p0);
SELECT [StudentId]
FROM [Students]
WHERE @@ROWCOUNT = 1 AND [StudentId] = scope_identity();',N'@p0 nvarchar(4000),
@p1 nvarchar(4000) ',@p0=N'Steve'
go
exec sp_executesql N'SET NOCOUNT ON;
INSERT INTO [StudentAddresses] ([Address], [City], [Country], [State], [StudentId])
VALUES (@p5, @p6, @p7, @p8, @p9);
SELECT [StudentAddressId]
FROM [StudentAddresses]
WHERE @@ROWCOUNT = 1 AND [StudentAddressId] = scope_identity();
',N'@p5 nvarchar(4000),@p6 nvarchar(4000),@p7 nvarchar(4000),@p8 nvarchar(4000),
@p9 int',@p5=NULL,@p6=N'SFO',@p7=N'USA',@p8=N'CA',@p9=1
Go
插入多个记录
使用DbContext.AddRange
or DbSet.AddRange
方法一次添加多个实体。您不需要DbContext.Add
多次调用方法。
AddRange方法 | 描述 |
---|---|
void AddRange(IEnumerable<Object> entities) | 向具有已添加状态的DbContext添加相同或不同类型实体的列表。 |
void AddRange(param object[] entities) | 向具有已添加状态的DbContext添加具有相同或不同类型实体的数组。 |
void AddRangeAsync(IEnumerable<Object>, CancellationToken) | 将具有相同或不同类型实体的列表添加到具有已添加状态的DbContext的异步方法。 |
以下示例演示如何Student
使用AddRange 添加实体对象列表。
var studentList = new List<Student>() {
new Student(){ Name = "Bill" },
new Student(){ Name = "Steve" }
};
using (var context = new SchoolContext())
{
context.AddRange(studentList);
context.SaveChanges();
}
上面的示例将在Students
表中插入两个新记录。
您还可以添加不同类型实体的列表,如下所示。
var std1 = new Student(){ Name = "Bill" };
var std2 = new Student(){ Name = "Steve" };
var computer = new Course() { CourseName = "Computer Science" };
var entityList = new List<Object>() {
std1,
std2,
computer
};
using (var context = new SchoolContext())
{
context.AddRange(entityList);
// context.AddRange(std1, std2, computer);
context.SaveChanges();
}
在上面的示例中,entityList是一种类型List<Object>
。因此,它可以包含任何类型的实体。该AddRange()
方法将所有指定的实体添加到上下文中,SaveChanges()
并将一次性构建和执行INSERT语句。
EF Core通过在单个数据库往返中为所有上述实体执行INSERT语句来提高性能。上面的示例将在数据库中执行以下语句。
exec sp_executesql N'SET NOCOUNT ON;
INSERT INTO [Courses] ([CourseName], [Description])
VALUES (@p0, @p1);
SELECT [CourseId]
FROM [Courses]
WHERE @@ROWCOUNT = 1 AND [CourseId] = scope_identity();
DECLARE @inserted1 TABLE ([StudentId] int, [_Position] [int]);
MERGE [Students] USING (
VALUES (@p2, 0),
(@p3, 1)) AS i ([Name], _Position) ON 1=0
WHEN NOT MATCHED THEN
INSERT ([Name])
VALUES (i.[Name])
OUTPUT INSERTED.[StudentId], i._Position
INTO @inserted1;
SELECT [t].[StudentId] FROM [Students] t
INNER JOIN @inserted1 i ON ([t].[StudentId] = [i].[StudentId])
ORDER BY [i].[_Position];
',N'@p0 nvarchar(4000),@p1 nvarchar(4000),@p2 nvarchar(4000),@p3 nvarchar(4000)',
@p0=N'Computer Science',@p1=NULL,@p2=N'Steve',@p3=N'Bill'
go
使用DbSet插入数据
如前所述,您可以使用DbSet保存实体的实例,该实体将以与EF 6.x相同的方式转换为数据库中的INSERT / UPDATE / DELETE命令。
使用该DbSet<TEntity>.Add()
方法附加具有已添加状态的实体或DbSet<TEntity>.AddRange()
附加具有已添加状态的实体集合的方法,如下所示。
var std = new Student()
{
Name = "Bill"
};
using (var context = new SchoolContext())
{
context.Students.Add(std);
context.SaveChanges();
}
在上面的示例中,类型context.Students
是DbSet<Student>
类型。因此,我们只能添加Student
实体。该context.Students.Add(std)
附加的Student
实体以添加的状态的情况下,这将导致INSERT语句时的SaveChanges()
方法被调用。
在下一章中了解如何更新无连接的实体。
【江湖人士】(jhrs.com)原创文章,作者:江小编,如若转载,请注明出处:https://jhrs.com/2019/27140.html
扫码加入电报群,让你获得国外网赚一手信息。