【问题标题】:Insert to SqlLite database using EF always return 1 for Id使用 EF 插入 Sqlite 数据库总是返回 1 作为 Id
【发布时间】:2022-09-23 19:49:48
【问题描述】:

我有一个使用 sqlite 作为数据库的简单联系人应用程序。我首先使用 EF 代码来设计它的数据库。当我保存数据时,它的 Id 按预期在数据库中产生(自动增量),但是保存更改方法总是为 Id 返回 1。

如何获取最新的表 ID?

数据库上下文:

public class ApplicationDbContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder options)
    {
        string dbPath = DbPathGenerator.GetDbPath();

        options.UseSqlite($\"Data Source={dbPath}/LiteContactsDb.db\");
    }

    public DbSet<Person> Persons { get; set; }
    public DbSet<Address> Addresses { get; set; }
    public DbSet<Phone> Phones { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Person>()
            .HasMany<Address>()
            .WithOne(a => a.Person)
            .HasForeignKey(a => a.PersonId);

        modelBuilder.Entity<Person>()
            .HasMany<Phone>()
            .WithOne(a => a.Person)
            .HasForeignKey(a => a.PersonId);


        base.OnModelCreating(modelBuilder);
    }
}

保存方法:

    public bool SaveContact(PersonViewModel personViewModel, PhoneViewModel phoneViewModel, AddressViewModel addressViewModel)
    {
        bool result = false;

        try
        {
            Person person = new Person();

            person.FirstName = personViewModel.FirstName;
            person.LastName = personViewModel.LastName;
            person.Email = personViewModel.Email;

            _context.Persons.Add(person);
            var personId = _context.SaveChanges();

            Phone phone = new Phone();

            phone.PersonId = personId;
            phone.PhoneTitle = phoneViewModel.PhoneTitle;
            phone.PhoneNumber = phoneViewModel.PhoneNumber;

            Address address = new Address();

            address.PersonId = personId;
            address.AddressTitle = addressViewModel.AddressTitle;
            address.AddressString = addressViewModel.AddressString;
            address.PostalCode = addressViewModel.PostalCode;

            _context.Phones.Add(phone);
            _context.Addresses.Add(address);

            _context.SaveChanges();

            result = true;
        }
        catch (Exception ex)
        {
            result = false;
        }

        return result;
    }

_context.SaveChanges();总是返回 1。

谢谢

  • SaveChanges 返回受影响的行数,而不是 Id。 Id 应该反映在实体本身上。
  • 代码是错误的。 SaveChanges 仍然存在全部待定更改并设置 ID全部新对象。只需创建对象并根据需要将它们分配给属性,然后只调用 .Add(person).英孚将插入全部相关实体
  • 事实上,多次调用SaveChanges 是一个代码错误。 DbContext 是一个工作单元。它跟踪在其生命周期内所做的所有更改。如果您处置它,更改将丢失。 SaveChanges 应该只在最后一刻被调用才能坚持全部单个内部事务中的未决更改。这样,即使发生错误,更改也会“回滚”

标签: c# sqlite entity-framework


【解决方案1】:

SaveChanges的返回值不是新创建记录的id,而是变化的次数。因此,如果您插入单个项目,则返回值将始终为 1。

如果要访问新插入对象的 id,请查看对象的 id-property。它在插入后更新。

【讨论】:

    【解决方案2】:

    首先,SaveChanges 返回受影响的行数,而不是存储对象时生成的任何 ID。二、SaveChanges 坚持全部待处理的更改,而不仅仅是单个对象。 DbContext 是断开连接的工作单元,而不是数据库连接。在必须加载数据或保存更改之前,它甚至不会保持连接打开。

    SaveChanges 被调用持久化全部变化,而不仅仅是最新的。发生这种情况时,将打开一个新连接,并且所有更改都保存在单个内部事务中。这意味着回滚工作单元不需要额外的努力——只是在处理 DbContext 之前不要调用SaveChanges

    最后,无需单独添加对象。调用.Add(person) 会将所有可通过它访问的对象添加到Added 状态。当更改持续存在时,DbContext 将以正确的顺序执行 INSERT 操作并自动修复 FK 属性。

    这意味着在一个一致的“事务”中添加一个人、电话和地址只需要这个:

    var person = new Person {
        FirstName = personViewModel.FirstName,
        LastName = personViewModel.LastName,
        Email = personViewModel.Email
       
        Phone = new Phone {
            PhoneTitle = phoneViewModel.PhoneTitle,
            PhoneNumber = phoneViewModel.PhoneNumber
        },
        
        Address = new Address {
            AddressTitle = addressViewModel.AddressTitle,
            AddressString = addressViewModel.AddressString,
            PostalCode = addressViewModel.PostalCode
         }
    }
    _context.Persons.Add(person);
    
    ...
    _context.SaveChanges();
    

    【讨论】:

      猜你喜欢
      • 2011-05-05
      • 1970-01-01
      • 1970-01-01
      • 2013-02-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-17
      相关资源
      最近更新 更多