jk's notes
  • 更新数据

更新数据

本章中, 我会介绍如何使用 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.

Last Updated:
Contributors: jk