1. 江湖人士首页
  2. IT江湖

Entity Framework Core无连接的场景插入数据

您了解了如何在连接的方案中保存数据。在这里,您将学习如何在无连接的场景中保存数据。

在无连接的方案中保存数据与连接方案中的数据略有不同。在无连接的方案中,DbContext不知道无连接的实体,因为实体是在当前DbContext实例的范围之外添加或修改的。因此,您需要将无连接的实体附加到适当的上下文,EntityState以便对数据库执行CUD(创建,更新,删除)操作。

下图说明了无连接方案中的CUD操作:

Entity Framework Core无连接的场景插入数据 1

根据上图,未被其跟踪的实体DbContext需要附加到DbContext适当的实体EntityState。例如,为新实体添加状态,已编辑实体的已修改状态和已删除实体的已删除状态,这将在SaveChanges()调用方法时在数据库中生成INSERT,UPDATE或DELETE命令。

必须执行以下步骤,以便在断开连接的方案中使用Entity Framework Core将记录插入,更新或删除到DB表中:

  1. 将实体附加到DbContext适当的EntityState例如添加,修改或删除
  2. 通话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();
}

在上面的示例中,stdStudent实体的无连接的实例。该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语句如上。

实体框架核心提供以下方法DbContextDbSet方法,将已断开连接的实体与Added相连EntityState,而后者又将在数据库中执行INSERT语句。

DbContext方法DbSet方法描述
DbContext.AttachDbSet.Attach将实体附加到DbContext。为Key属性具有值的实体设置Unchanged状态,为Key属性为空的实体或数据类型的默认值设置Added状态。
DbContext.AddDbSet.Add将实体附加到具有已添加状态的DbContext。
DbContext.AddRangeDbSet.AddRange将实体集合附加到具有已添加状态的DbContext。
DbContext.Entry获取EntityEntry指定实体,该实体提供对更改跟踪信息和操作的访问权限。
DbContext.AddAsyncDbSet.AddAsync将实体附加到具有已添加状态的DbContext的异步方法,如果没有则开始跟踪它。调用SaveChangesAsync()时,数据将插入数据库。
DbContext.AddRangeAsyncDbSet.AddRangeAsync将多个实体附加到具有添加状态的DbContext的异步方法,如果没有,则开始跟踪它们。调用SaveChangesAsync()时,数据将插入数据库。

注意:上述DbContext方法是在EF Core中引入的(它们在EF 6或之前版本中不可用)。两者DbContextDbSet方法执行相同的操作。您使用哪一个取决于您的编码模式和偏好。

插入关系数据

在上一章中,我们学会了在两个实体之间创建一对一,一对多和多对多的关系。实体框架API插入相关实体中包含的所有关系数据。

使用DbContext.Addor 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通过引用导航属性StudentEntityState两个要添加的实体的标记到达实例,这将构建并执行以下两个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.AddRangeor 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.StudentsDbSet<Student>类型。因此,我们只能添加Student实体。该context.Students.Add(std)附加的Student实体以添加的状态的情况下,这将导致INSERT语句时的SaveChanges()方法被调用。

在下一章中了解如何更新无连接的实体。

本站最新优惠

Namesilo优惠:新用户省 $1 域名注册-优惠码:45D%UYTcxYuCloZ 国外最便宜域名!点击了解更多

特别优惠:免费赠送 $100 Vultr主机-限时优惠!英文站必备海外服务器!点击了解更多

VPS优惠:搬瓦工优惠码:BWH3OGRI2BMW 最高省5.83%打开外面世界的一款主机点击了解更多

原创文章,作者:江小编,如若转载,请注明出处:https://jhrs.com/2019/27140.html

扫码关注【江湖人士】公众号,您会获得关于国外被动收入的最新资讯

WA付费会员QQ群:387027533,加这个群需要回答您的WA会员名,待核实后予以通过

普通QQ交流群:178758794,可分享交流建站的各类经验和知识

发表评论

电子邮件地址不会被公开。 必填项已用*标注

15 + 16 =