更新数据
本章中, 我会介绍如何使用 Entity Framework Core 5 来更新数据库中已存在的数据. 我还会介绍如何更新根实体, 以及与其相关联的子实体.
更新根实体
一个简单的更新实体的方法是, 首先查询数据, 然后修改需要更新的属性, 然后通过 SaveChanges
来提交修改. 例如, 要根据 Id
来更新一条记录, 你首先通过该 Id
查询出该记录, 然后修改属性值, 然后通过上下文提交修改, 如下:
using (var context = new AppDbContext())
{
var person = context.Persons.Signle(x => x.Id == 1);
person.FirstName = "Kent";
person.LastName = "Jones";
context.SaveChanges();
}
如果你无法确认数据记录是否存在, 你可以使用 SingleOrDefault
来代替 Single
来查询记录. 在使用该方法时, 你应该总是检查 null
. 否则你可能获得 null
引用而引发异常. 新代理看起来像:
using (var context = new AppDbContext())
{
var person = context.Persons.SingleOrDefault(x => x.Id == 1);
if(person != null)
{
person.FirstName = "Kent";
person.LastName = "jones";
context.SaveChanges();
}
}
在这个案例中, 我们首先根据 Id
为 1
来查询该数据, 如果数据记录存在, 我们再更新其 FirstName
和 LastName
属性, 并保存修改.
更新子实体
你可以使用与更新根实体一样的方法直接更新子实体, 也可以使用在根实体上利用导航属性来更新子实体. 例如, 更新 person
的第一个地址中的 AddressLine1
的值, 你需要先获得 person
记录, 然后通过导航属性修改第一个 address
属性, 然后调用 SaveChanges
, 如下:
using (var constext = new AppDbContext())
{
var person = context.Persons.SingleOrDefault(x => x.Id == 1);
if (person != null)
{
person.Addresses.First().AddressLine1 = "1234 New Street";
context.SaveChanges();
}
}
如果你知道子实体的主键值, 你可以直接更新子实体, 就好像根实体一样:
using (var context = new AppDbContext())
{
var address = context.Addresses.SingleOrDefault(x => x.Id == 1);
if (address != null)
{
address.AddressLine1 = "1234 New Street";
context.SaveChanges();
}
}
在上面的代码中, 我们试图获得一条 Id
为 1
的地址记录. 如果地址记录存在, 然后我们更新 AddressLine1
的值, 然后保存该变化.
集成测试
现在, 你已经知道更新数据的基本操作了, 让我们创建一个集成测试来看看. 在 DAL.Tests
项目中创建一个 UpdateTests
类. 第一步, 我们要创建 SetUp
方法, 它会添加一个新的测试记录用于更新测试, 如下:
private AppDbCOntext _context;
private int _personId;
[SetUp]
public void SetUp()
{
_context = new AppDbCOntext(
DbContextOptionsBuilder<AppDbContext>()
.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=EfCore5WebApp;Trusted_Connection=True;MultipleActiveResultSets=True")
.Options
);
var record = new Person()
{
FirstName = "Clarke",
LastName = "Kent",
CreatedOn = DateTime.Now,
EmailAddress = "clark@daileybugel.com",
Addresses = new List<Person>
{
new Address
{
AddressLine1 = "1234 Fake Street",
AddressLine2 = "Suite 1",
City = "Chicage",
State = "IL",
ZipCode = "60652",
Country = "United States"
}
}
};
_context.Person.Add(record);
_context.SaveChanges();
_personId = record.Id;
}
现在我们已经设置了用于测试的数据记录以及所插入数据的 Id
. 下面, 在我们来测试更新逻辑之前, 我们来实现 TearDown
方法. TearDown
方法十分简单, 就是查询出插入的 person
数据, 并删除它:
[TearDown]
public void TearDown()
{
var person = _context.Persons.Single(x => x.Id == _personId);
_context.Persons.Remove(person);
_context.SaveChanges();
}
最后一个步骤是实现测试方法, 它会根据 Id
查询出已存在的数据, 然后更新该数据, 以及与其相关联的地址数据. 然后我们执行 SaveChanges
来更新. 在那之后, 我们查询 person
, 并验证它是否完成更新. 看下面测试的实现:
[Test]
public void UpdatePersonWithAddresses()
{
var person = _context.Persons.Signle(x => x.Id == _personId);
string firstName = "Matt";
string lastName = "Smith";
string email = "doctor@who.com";
person.FirstName = firstName;
person.LastName = lastName;
person.EmailAddress = email;
var address = person.Addresses.First();
string addressLine1 = "123 Update Street";
string addressLine2 = "APT B1";
string city = "Okemos";
string state = "MI";
string country = "USA";
string zipCode = "48864";
address.AddressLine1 = addressLine1;
address.AddressLine2 = addressLine2;
address.City = city;
address.State = state;
address.Country = country;
address.ZipCode = zipCode;
_context.SaveChanges();
var updatePerson = _context.Persons.Single(x => x.Id == _personId);
Assert.AreEqual(1, updatePerson.Addresses.Count);
Assert.AreEqual(firstName, updatePerson.Firstname);
...
}
你最终的测试文件应该看起来像:
...
小结
本章中, 我们介绍了如何使用 EF Core 5 来更新实体记录. 基本步骤是先查询需要更新的记录, 然后修改属性. 最后调用 SaveChanges
去持久化更新. 下一章, 我们会介绍删除数据的策略, 使用 EF Core 5.