如何使用实体框架核心更新记录?

Cha*_*ith 44 entity-framework-6 entity-framework-core .net-core

在实体框架工作核心中更新数据库表数据的最佳方法是什么?

  1. 返回表格行,进行更改并保存
  2. 在db上下文中使用关键字Update,并处理项不存在的异常

我们可以在EF6上使用哪些改进功能?

H. *_*rzl 56

要使用Entity Framework Core更新实体,这是一个逻辑过程:

  1. DbContext类创建实例
  2. 按键检索实体
  3. 对实体的属性进行更改
  4. 保存更改

Update()方法DbContext:

开始跟踪处于Modified状态的给定实体,以便在SaveChanges()调用时在数据库中更新它.

Update方法不保存数据库中的更改; 相反,它为DbContext实例中的条目设置状态.

因此,我们可以Update()在保存数据库更改之前调用方法.

我会假设一些对象定义来回答你的问题:

  1. 数据库名称是Store

  2. 表名是Product

产品类定义:

public class Product
{
    public int? ProductID { get; set; }

    public string ProductName { get; set; }

    public string Description { get; set; }

    public decimal? UnitPrice { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

DbContext类定义:

public class StoreDbContext : DbContext
{
    public DbSet<Product> Products { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("Your Connection String");

        base.OnConfiguring(optionsBuilder);
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Order>(entity =>
        {
            // Set key for entity
            entity.HasKey(p => p.ProductID);
        });

        base.OnModelCreating(modelBuilder);
    }
}
Run Code Online (Sandbox Code Playgroud)

更新实体的逻辑:

using (var context = new StoreDbContext())
{
        // Retrieve entity by id
        // Answer for question #1
        var entity = context.Products.FirstOrDefault(item => item.ProductID == id);

        // Validate entity is not null
        if (entity != null)
        {
            // Answer for question #2

            // Make changes on entity
            entity.UnitPrice = 49.99m;
            entity.Description = "Collector's edition";

            // Update entity in DbSet
            context.Products.Update(entity);

            // Save changes in database
            context.SaveChanges();
        }
}
Run Code Online (Sandbox Code Playgroud)

如果这有用,请告诉我

  • 事实上,context.Products.Update 行是多余的,因为一旦从上下文中检索实体,就会对其进行跟踪。以下是不同方法的精彩概述:https://www.learnentityframeworkcore.com/dbcontext/modifying-data (9认同)

Sha*_*dam 38

public async Task<bool> Update(MyObject item)
{
    Context.Entry(await Context.MyDbSet.FirstOrDefaultAsync(x => x.Id == item.Id)).CurrentValues.SetValues(item);
    return (await Context.SaveChangesAsync()) > 0;
}
Run Code Online (Sandbox Code Playgroud)


Ehs*_*edi 34

根据微软的文档:

read-first方法需要额外的数据库读取,并且可能导致更复杂的代码以处理并发冲突

但是,您应该知道在DbContext上使用Update方法会将所有字段标记为已修改,并将在查询中包含所有字段.如果要更新字段子集,则应使用Attach方法,然后将所需字段标记为手动修改.

context.Attach(person);
context.Entry(person).Property("Name").IsModified = true;
context.SaveChanges();
Run Code Online (Sandbox Code Playgroud)

  • 只是小版本,现在有这个API的更强类型版本:`context.Entry(person).Property(p => p.Name).IsModified = true;` (16认同)
  • 也可以简单地执行`context.Entry(person).State = EntityState.Modified;` (2认同)
  • 好点ehsan jan!;D 另外,如果实体是由用户更新的,而你不知道/关心哪些字段被修改,你可以使用 `_context.Attach(person).State = EntityState.Modified; ` 表示该实体应在 SaveChanges 方法中更新。 (2认同)

The*_*ist 22

假设我们有一个实体StudentAppDbContext如下所示。

class Student
{
    public int Id { get; set; }
    public string Name { get; set; } = default!;
    public int Age { get; set; }
}


public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> opts) : base(opts) { }

    public DbSet<Student> Students { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

A版

  • CurrentValues只能对跟踪实体 ( found) 起作用。
  • 仅更改的属性被标记为Modified
  • TEntity当使用类型参数而不是固定类型时,自动属性映射非常有用Student
async Task Edit_A(int id, Student incoming, AppDbContext db)
{
    if (await db.Students.FindAsync(id) is Student found)
    {
        db.Entry(found).CurrentValues.SetValues(incoming);

        await db.SaveChangesAsync();
    }
}
Run Code Online (Sandbox Code Playgroud)

B版

  • 它仅适用于被跟踪的实体 ( found)。
  • 没有必要映射所有属性,因为只有更改的属性才会被标记为Modified
  • 手动属性映射,因此我们不能不使用泛型类型参数。
async Task Edit_B(int id, Student incoming, AppDbContext db)
{
    if (await db.Students.FindAsync(id) is Student found)
    {
        found.Name = incoming.Name;
        found.Age = incoming.Age; 
        

        await db.SaveChangesAsync();
    }
}
Run Code Online (Sandbox Code Playgroud)

C版

  • Update()仅适用于未跟踪的实体 ( incoming) 并使其被跟踪。found调用前取消跟踪Update(incoming)是强制性的,因为使用给定的主键只能跟踪一个实体。
  • 所有属性(包括未更改的属性)都标记为Modified。它的效率较低。
  • 自动属性映射对于泛型类型参数很有用。
async Task Edit_C(int id, Student incoming, AppDbContext db)
{
    if (await db.Students.FindAsync(id) is Student found)
    {
        db.Students.Entry(found).State = EntityState.Detached;
        db.Students.Update(incoming);
        await db.SaveChangesAsync();
    }
}
Run Code Online (Sandbox Code Playgroud)

D版

  • 它与C版本相同。为了完整起见,我在下面再次重写。
  • 它仅适用于未跟踪的实体 ( incoming) 并使其被跟踪。取消跟踪found是强制性的,因为只能使用给定的主键跟踪一个实体。
  • 所有属性(包括未更改的属性)都标记为Modified。它的效率较低。
  • 自动属性映射对于泛型类型参数很有用。
async Task Edit_D(int id, Student incoming, AppDbContext db)
{
    if (await db.Students.FindAsync(id) is Student found)
    {
        db.Students.Entry(found).State = EntityState.Detached;
        db.Students.Entry(incoming).State = EntityState.Modified;
        await db.SaveChangesAsync();
    }
}
Run Code Online (Sandbox Code Playgroud)

E版

  • 它仅适用于未跟踪的实体 ( incoming) 并使其被跟踪。取消跟踪found是强制性的,因为只能使用给定的主键跟踪一个实体。
  • 没有必要映射所有属性,因为只有 标记的属性(包括未更改的属性)IsModified=true才会更新。如果标记IsModified=true未更改的属性,效率会降低。
  • 手动属性映射,因此我们不能不使用泛型类型参数。
async Task Edit_E(int id, Student incoming, AppDbContext db)
{
    if (await db.Students.FindAsync(id) is Student found)
    {
        db.Students.Entry(found).State = EntityState.Detached;
        db.Students.Entry(incoming).Property(s => s.Name).IsModified = true;
        db.Students.Entry(incoming).Property(s => s.Age).IsModified = true;
        await db.SaveChangesAsync();
    }
}
Run Code Online (Sandbox Code Playgroud)

我将其设置为社区 Wiki,您可以随意编辑。


Mel*_*per 10

超级简单

using (var dbContext = new DbContextBuilder().BuildDbContext())
{
    dbContext.Update(entity);
    await dbContext.SaveChangesAsync();
}
Run Code Online (Sandbox Code Playgroud)


Nip*_*una 9

Microsoft Docs为我们提供了两种方法。

推荐的HttpPost 编辑代码:读取和更新

这与我们在以前版本的实体框架中使用的旧方法相同。这就是微软为我们推荐的。

好处

  • 防止过度发布
  • EF 自动更改跟踪Modified在由表单输入更改的字段上设置标志。

替代HttpPost 编辑代码:创建并附加

另一种方法是将模型绑定器创建的实体附加到 EF 上下文并将其标记为已修改。

正如另一个答案中提到的,读取优先方法需要额外的数据库读取,并且可能会导致处理并发冲突的代码更加复杂。