Entity Framework Core无连接的场景更新数据,EF Core API在数据库中为EntityState已修改的实体构建并执行UPDATE语句。在连接的场景中,DbContext跟踪所有实体,以便它知道哪些被修改,因此自动设置EntityState为Modified。
Entity Framework Core无连接的场景更新数据,EF Core API在数据库中为EntityState
已修改的实体构建并执行UPDATE语句。在连接的场景中,DbContext
跟踪所有实体,以便它知道哪些被修改,因此自动设置EntityState
为Modified。
Entity Framework Core无连接的场景更新数据
在诸如Web应用程序 之类的无连接的场景中,DbContext
由于实体被修改为超出当前DbContext
实例的范围,因此不知道实体。因此,首先我们需要将无连接的实体附加到DbContext
具有Modified 的实例EntityState
。
Entity Framework Core无连接的场景更新数据
下表列出了更新实体的方法DbContext
和DbSet
方法:
DbContext方法 DbSet方法 描述 DbContext.Update DbSet.Update 将实体附加到具有修改状态的DbContext。 DbContext.UpdateRange DbSet.UpdateRange 将实体集合附加到具有已修改状态的DbContext。
Entity Framework Core无连接,以下示例演示如何更新断开连接的实体。
// Disconnected Student entity
var stud = new Student (){ StudentId = 1 , Name = "Bill" } ;
using ( var context = new SchoolContext ())
context. Update < Student >( stud ) ;
// or the followings are also valid
// context.Students.Update(stud);
// context.Attach<Student>(stud).State = EntityState.Modified;
// context.Entry<Student>(stud).State = EntityState.Modified;
// Disconnected Student entity
var stud = new Student(){ StudentId = 1, Name = "Bill" };
stud.Name = "Steve";
using (var context = new SchoolContext())
{
context.Update<Student>(stud);
// or the followings are also valid
// context.Students.Update(stud);
// context.Attach<Student>(stud).State = EntityState.Modified;
// context.Entry<Student>(stud).State = EntityState.Modified;
context.SaveChanges();
}
// Disconnected Student entity
var stud = new Student(){ StudentId = 1, Name = "Bill" };
stud.Name = "Steve";
using (var context = new SchoolContext())
{
context.Update<Student>(stud);
// or the followings are also valid
// context.Students.Update(stud);
// context.Attach<Student>(stud).State = EntityState.Modified;
// context.Entry<Student>(stud).State = EntityState.Modified;
context.SaveChanges();
}
在上面的示例中,请考虑stud
现有Student
实体对象,因为它具有有效的Key属性值(StudentId = 1)。Entity Framework Core引入了DbContext.Update()
将指定实体附加到上下文并将其设置EntityState
为Modified的方法。或者,您也可以使用DbSet.Update()
方法(context.Students.Update(stud)
)来执行相同的操作。
上面的示例在数据库中执行以下UPDATE语句。
exec sp_executesql N 'SET NOCOUNT ON;
UPDATE [Students] SET [Name] = @p0
' ,N '@p1 int,@p0 nvarchar(4000)' ,@p1= 1 ,@p0=N 'Steve'
exec sp_executesql N'SET NOCOUNT ON;
UPDATE [Students] SET [Name] = @p0
WHERE [StudentId] = @p1;
SELECT @@ROWCOUNT;
',N'@p1 int,@p0 nvarchar(4000)',@p1=1,@p0=N'Steve'
go
exec sp_executesql N'SET NOCOUNT ON;
UPDATE [Students] SET [Name] = @p0
WHERE [StudentId] = @p1;
SELECT @@ROWCOUNT;
',N'@p1 int,@p0 nvarchar(4000)',@p1=1,@p0=N'Steve'
go
更新多个实体
使用DbContext.UpdateRange
or DbSet.UpdateRange
方法将实体的集合或数组附加到其中DbContext
,并将它们EntityState
一次性设置为Modified。
var modifiedStudent1 = new Student ()
var modifiedStudent2 = new Student ()
var modifiedStudent3 = new Student ()
IList < Student > modifiedStudents = new List < Student >()
using ( var context = new SchoolContext ())
context. UpdateRange ( modifiedStudents ) ;
// or the followings are also valid
//context.UpdateRange(modifiedStudent1, modifiedStudent2, modifiedStudent3);
//context.Students.UpdateRange(modifiedStudents);
//context.Students.UpdateRange(modifiedStudent1, modifiedStudent2, modifiedStudent3);
var modifiedStudent1 = new Student()
{
StudentId = 1,
Name = "Bill"
};
var modifiedStudent2 = new Student()
{
StudentId = 3,
Name = "Steve"
};
var modifiedStudent3 = new Student()
{
StudentId = 3,
Name = "James"
};
IList<Student> modifiedStudents = new List<Student>()
{
modifiedStudent1,
modifiedStudent2,
modifiedStudent3
};
using (var context = new SchoolContext())
{
context.UpdateRange(modifiedStudents);
// or the followings are also valid
//context.UpdateRange(modifiedStudent1, modifiedStudent2, modifiedStudent3);
//context.Students.UpdateRange(modifiedStudents);
//context.Students.UpdateRange(modifiedStudent1, modifiedStudent2, modifiedStudent3);
context.SaveChanges();
}
var modifiedStudent1 = new Student()
{
StudentId = 1,
Name = "Bill"
};
var modifiedStudent2 = new Student()
{
StudentId = 3,
Name = "Steve"
};
var modifiedStudent3 = new Student()
{
StudentId = 3,
Name = "James"
};
IList<Student> modifiedStudents = new List<Student>()
{
modifiedStudent1,
modifiedStudent2,
modifiedStudent3
};
using (var context = new SchoolContext())
{
context.UpdateRange(modifiedStudents);
// or the followings are also valid
//context.UpdateRange(modifiedStudent1, modifiedStudent2, modifiedStudent3);
//context.Students.UpdateRange(modifiedStudents);
//context.Students.UpdateRange(modifiedStudent1, modifiedStudent2, modifiedStudent3);
context.SaveChanges();
}
如您所见,该UpdateRange
方法有两个重载。一个重载采用实体集合,第二个重载object[]
作为参数。该DbSet.UpdateRange
方法与该方法的工作方式相同DbContext.UpdateRange
。
EF Core通过为上例中的所有实体构建UPDATE语句来提高性能,并在单个数据库往返中 执行它。
exec sp_executesql N 'SET NOCOUNT ON;
UPDATE [Students] SET [Name] = @p0
UPDATE [Students] SET [Name] = @p2
UPDATE [Students] SET [Name] = @p4
' ,N '@p1 int,@p0 nvarchar(4000),@p3 int,@p2 nvarchar(4000),@p5 int,@p4 nvarchar(4000)' ,
@p1= 1 ,@p0=N 'Bill' ,@p3= 2 ,@p2=N 'Steve' ,@p5= 3 ,@p4=N 'James'
exec sp_executesql N'SET NOCOUNT ON;
UPDATE [Students] SET [Name] = @p0
WHERE [StudentId] = @p1;
SELECT @@ROWCOUNT;
UPDATE [Students] SET [Name] = @p2
WHERE [StudentId] = @p3;
SELECT @@ROWCOUNT;
UPDATE [Students] SET [Name] = @p4
WHERE [StudentId] = @p5;
SELECT @@ROWCOUNT;
',N'@p1 int,@p0 nvarchar(4000),@p3 int,@p2 nvarchar(4000),@p5 int,@p4 nvarchar(4000)',
@p1=1,@p0=N'Bill',@p3=2,@p2=N'Steve',@p5=3,@p4=N'James'
go
exec sp_executesql N'SET NOCOUNT ON;
UPDATE [Students] SET [Name] = @p0
WHERE [StudentId] = @p1;
SELECT @@ROWCOUNT;
UPDATE [Students] SET [Name] = @p2
WHERE [StudentId] = @p3;
SELECT @@ROWCOUNT;
UPDATE [Students] SET [Name] = @p4
WHERE [StudentId] = @p5;
SELECT @@ROWCOUNT;
',N'@p1 int,@p0 nvarchar(4000),@p3 int,@p2 nvarchar(4000),@p5 int,@p4 nvarchar(4000)',
@p1=1,@p0=N'Bill',@p3=2,@p2=N'Steve',@p5=3,@p4=N'James'
go
更改实体状态EntityState
该Update
方法EntityState
基于key属性的值设置。如果根或子实体的key属性为空,指定数据类型的null或默认值,则该Update()
方法将其视为新实体,并将其设置EntityState
为Entity Framework Core 2.x中的Added。
public static void Main ()
var newStudent = new Student ()
var modifiedStudent = new Student ()
using ( var context = new SchoolContext ())
context. Update < Student >( newStudent ) ;
context. Update < Student >( modifiedStudent ) ;
DisplayStates ( context. ChangeTracker . Entries ()) ;
private static void DisplayStates ( IEnumerable < EntityEntry > entries )
foreach ( var entry in entries )
Console. WriteLine ( $ "Entity: {entry.Entity.GetType().Name},
State: {entry.State.ToString()} " ) ;
public static void Main()
{
var newStudent = new Student()
{
Name = "Bill"
};
var modifiedStudent = new Student()
{
StudentId = 1,
Name = "Steve"
};
using (var context = new SchoolContext())
{
context.Update<Student>(newStudent);
context.Update<Student>(modifiedStudent);
DisplayStates(context.ChangeTracker.Entries());
}
}
private static void DisplayStates(IEnumerable<EntityEntry> entries)
{
foreach (var entry in entries)
{
Console.WriteLine($"Entity: {entry.Entity.GetType().Name},
State: {entry.State.ToString()} ");
}
}
public static void Main()
{
var newStudent = new Student()
{
Name = "Bill"
};
var modifiedStudent = new Student()
{
StudentId = 1,
Name = "Steve"
};
using (var context = new SchoolContext())
{
context.Update<Student>(newStudent);
context.Update<Student>(modifiedStudent);
DisplayStates(context.ChangeTracker.Entries());
}
}
private static void DisplayStates(IEnumerable<EntityEntry> entries)
{
foreach (var entry in entries)
{
Console.WriteLine($"Entity: {entry.Entity.GetType().Name},
State: {entry.State.ToString()} ");
}
}
Output: Entity: Student, State: Added Entity: Student, State: Modified
在上面的示例中,newStudent
没有Key属性值(StudentId)。因此,该Update()
方法将其标记为已添加,而modifiedStudent具有值,因此它将标记为已修改。
异常:
该Update
和UpdateRange
方法抛出InvalidOperationException
,如果实例DbContext
已经跟踪具有相同键的属性值的实体。请考虑以下示例:
var student = new Student ()
using ( var context = new SchoolContext ())
// loads entity in a conext whose StudentId is 1
context. Students . First < Student >( s = > s. StudentId == 1 ) ;
// throws an exception as it already tracking entity with StudentId=1
context. Update < Student >( student ) ;
var student = new Student()
{
StudentId = 1,
Name = "Steve"
};
using (var context = new SchoolContext())
{
// loads entity in a conext whose StudentId is 1
context.Students.First<Student>(s => s.StudentId == 1);
// throws an exception as it already tracking entity with StudentId=1
context.Update<Student>(student);
context.SaveChanges();
}
var student = new Student()
{
StudentId = 1,
Name = "Steve"
};
using (var context = new SchoolContext())
{
// loads entity in a conext whose StudentId is 1
context.Students.First<Student>(s => s.StudentId == 1);
// throws an exception as it already tracking entity with StudentId=1
context.Update<Student>(student);
context.SaveChanges();
}
在上面的示例中,context
对象加载的Student
实体StudentId
为1并开始跟踪它。因此,附加具有相同键值的实体将引发以下异常:
无法跟踪实体类型“Student”的实例,因为已经跟踪了另一个具有{‘StudentId’}相同键值的实例。附加现有实体时,请确保仅附加具有给定键值的一个实体实例。考虑使用’DbContextOptionsBuilder.EnableSensitiveDataLogging’来查看冲突的键值。
下一章将学习在无连接中删除数据。
【江湖人士】(jhrs.com)原创文章,作者:江小编,如若转载,请注明出处:https://jhrs.com/2019/27162.html
扫码加入电报群,让你获得国外网赚一手信息。
文章标题:Entity Framework Core无连接的场景更新数据