如何在Entity Framework (Core)中仅更新特定字段?

7
我正在编写一个应用程序,它从外部API获取数据并使用Entity Framework将其存储到我的SQL Server数据库中。我每天从这个API拉取数据,所以如果一行已经存在,记录将被更新,否则将创建一个新记录。这是通过检查Id来完成的。
现在我遇到的问题是,我只想让EF更新BranchIdCustomerNameTopdeskCustomerNamePRTG的值由我手动添加到数据库中。因此,当记录被更新时,它会被设置为空,并且我手动插入的值将丢失。 更新之前

enter image description here

更新后

After

API返回的数据会被反序列化为JSON格式,并存储在 data 变量中,类型为 List<Customers>。我正在使用以下代码检查记录是否已经存在,如果存在则更新它,否则创建一个新记录。可以看到目前整个 Customer 记录都在被更新,包括值为 NULL 的 CustomerNamePRTG 字段。
string apiResponse = await response.Content.ReadAsStringAsync();

var data = JsonConvert.DeserializeObject<List<Customers>>(apiResponse);

foreach (Customers customer in data)
{
    if (db.Customers.Any(x => x.BranchId == customer.BranchId))
    {
        db.Customers.Update(customer);
    }
    else
    {
        db.Customers.Add(customer);
    }

    db.SaveChanges();
}

模型

public class Customers
{
    [Key]
    [JsonProperty("id")]
    public string BranchId { get; set; }

    [JsonProperty("name")]
    public string CustomerNameTopdesk { get; set; }

    public string CustomerNamePRTG { get; set; }
}

DbContext

public DbSet<Customers> Customers { get; set; }
3个回答

7
您需要更新EF返回的实体。
string apiResponse = await response.Content.ReadAsStringAsync();

var data = JsonConvert.DeserializeObject<List<Customers>>(apiResponse);

foreach (Customers customer in data)
{
    var current = db.Customers.Find(customer.BranchId);
    if (current != null)
    {
        db.Entry(current).CurrentValues.SetValues(customer);
    }
    else
    {
        db.Customers.Add(customer);
    }

    db.SaveChanges();
}

谢谢你的回答,这正是我所寻找的。 - Bram
1
那么为了更新一个列就要额外往返于数据库一次吗?我知道我曾经看到过如何在不首先从数据库查询对象的情况下完成此操作。 - johnw182

5

您只能为单个字段分配值。

string apiResponse = await response.Content.ReadAsStringAsync();

var data = JsonConvert.DeserializeObject<List<Customers>>(apiResponse);

foreach (Customers customer in data)
{
    var record = db.Customers.Find(customer.BranchId);
    if (record != null)
    {
        record.BranchId = customer.BranchId;
        // as many fields as you need
 
        db.Customers.Update(record );
    }
    else
    {
        db.Customers.Add(customer);
    }

    db.SaveChanges();
}

谢谢你的回答! - Bram

0

虽然这些答案中有一些可以工作,但所有答案都极其低效。特别是在您需要逐个更新多个记录的情况下。

看起来您有不连续的实体,因此重要的是要避免为每个记录向数据库服务器发出一次往返请求。这些其他答案会进行两次到数据库的访问,一次获取实体,一次更新。对于您列表中的每条记录都这样操作。

尝试这个:

string apiResponse = await response.Content.ReadAsStringAsync();

var data = JsonConvert.DeserializeObject<List<Customers>>(apiResponse);

foreach (Customers customer in data) {
    var current = new db.Customer();
    current.BranchID = customer.BranchID; // Set the identity
    db.Attach(current); // Starts change tracking
    current.CustomerNameTopdesk = customer.CustomerNameTopdesk; // Any props updated after the .Attach() will be automatically tracked as changed.
    current.CustomerNamePRTG = customer.CustomerNamePRTG;
    // Any properties NOT changed after .Attach() WILL NOT be included in the the generated UPDATE statement.
}

db.SaveChanges();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接