是否可以强制 DbContext.MyTable.Local 成员在 DbContext.SaveChanges() 执行之前分配自动 ID? (EFCore + SQLite)

Posted

技术标签:

【中文标题】是否可以强制 DbContext.MyTable.Local 成员在 DbContext.SaveChanges() 执行之前分配自动 ID? (EFCore + SQLite)【英文标题】:Is it possible to enforce DbContext.MyTable.Local members to have auto ID assigned before DbContext.SaveChanges() execution? (EFCore + SQLite) 【发布时间】:2020-03-03 17:41:41 【问题描述】:

所以我在实际保存之前尝试访问我的本地(或者您可以称之为“临时/运行时/RAM”)数据库(使用带有 EF Core 的 SQLite)它在硬盘上。发现我可以使用DbContext.MyTable.Local 访问本地myTable,但问题是尚未分配ID 的自动增量。那么我可以强制我的本地表成员在执行DbContext.SaveChanges() 之前自动分配ID 吗?如果没有,还有什么办法?

这是我的代码:

using System.Linq;

class Program

    private static MyDbContext _myDbContext = new MyDbContext();

    static void Main(string[] args)
    
        MyClass newClass = new MyClass()  Name = "MyName", Amount = 10 ;
        _myDbContext.MyClasses.ToList();    // forcing to have all members in "_myDbContext.MyClasses.Local". Otherwise only changed/added etc. members appear.
        _myDbContext.MyClasses.Add(newClass);

        int myNewID = newClass.ID; 
        // I need newClass.ID that has been auto-assigned here, but it's currently integer default so myNewID value is 0

        _myDbContext.SaveChanges();
        int myNewerId = newClass.ID;
        // now have new auto-assigned newClass.ID value but It's too late
    

我的模特:

class MyClass

    public int ID  get; set; 
    public string Name  get; set; 
    public int Amount  get; set; 

我的 DbContext:

using Microsoft.EntityFrameworkCore;

class MyDbContext : DbContext

    public DbSet<MyClass> MyClasses  get; set; 

    private static bool _created = false;
    public MyDbContext()
    
        if (!_created)
        
            _created = true;
            //Database.EnsureDeleted();
            Database.EnsureCreated();
        
    

    protected override void OnConfiguring(DbContextOptionsBuilder optionbuilder)
    
        optionbuilder.UseSqlite(@"Data Source=..\TestDB.db");
    

【问题讨论】:

您能否详细说明您要完成的工作,以及为什么在保存记录后获取 ID 为时已晚? 我试图让用户操作他的本地数据库并仅通过“保存到数据库”按钮将更改保存到实际数据库中。 为时已晚,因为我在保存到实际数据库之前将值(包括 ID)放在本地数据库中 我不确定您的特定用例,但您应该能够创建一个界面,用户可以在其中操作对象列表,然后将其保存到数据库中完毕。我不确定为什么在将 ID 保存到数据库之前需要分配 ID。 【参考方案1】:

在 EF 中,如果模型具有 ID 属性作为 int,它应该自动将其设置为 PK 和自动增量,除非您另有指定。如果问题只是“我可以在不保存到数据库的情况下获得自动生成的 ID”吗?答案是否定的,你不能。

为了获取自动生成的 ID 列的 ID,您必须先将更改保存到数据库。之后,将设置新记录的ID 属性。

MyClass newClass = new MyClass()  
  Name = "MyName", 
  Amount = 10 
;
_myDbContext.MyClasses.Add(newClass);
_myDbContext.SaveChanges();

//newClass.ID will be set here. 

如果您使用的是自动生成的列,这是唯一的方法。如果您想自己设置 ID - 比如使用 uuid - 您可以对 ID 列进行更改。对于涉及将 ID 列的类型更改为字符串的 uuid,您需要将 MaxLength 设置为您选择使用的任何长度。

class MyClass

    [MaxLength(50)]
    public string ID  get; set; 
    public string Name  get; set; 
    public int Amount  get; set; 

然后您可以在写入数据库更改之前手动分配 ID。

还有,在这一行

_myDbContext.MyClasses.ToList();    // forcing to have all members in "_myDbContext.MyClasses.Local". Otherwise only changed/added etc. members appear.

我不确定我是否理解您的逻辑,但是没有理由这样做只是为了将新记录保存到数据库中,并且随着数据库的增长,这样做会大大降低您的应用程序的速度。就目前而言,您正在请求表中每个项目的列表,但您甚至没有将其保存到变量中,因此这一行无非是为了减慢您的程序。

【讨论】:

所以,我需要保存数据库以获取 ID 值...我试图让用户操作他的本地数据库并通过“保存到数据库”按钮将更改保存到实际数据库。在你提到的最后一行代码中:如果我不放那一行,那么我的“MyTable.Local”成员只是我添加/更改的成员,其他未更改的成员没有显示。在调试模块 VS2019 上说:“扩展结果视图将枚举 IEnumerable”所以我相信通过调用 .ToList() 方法读取所有成员以某种方式将所有成员签名为“已更改”(或类似的东西),这样我就可以看到所有成员

以上是关于是否可以强制 DbContext.MyTable.Local 成员在 DbContext.SaveChanges() 执行之前分配自动 ID? (EFCore + SQLite)的主要内容,如果未能解决你的问题,请参考以下文章

是否可以强制网站输入为英文?

来自 MYSQL 中某个范围的 Entity Framework Core 随机记录

是否可以在 NetConnection 上强制使用源端口?

是否可以通过 Wifi 或 TMobile 网络强制网络流量?

是否可以选择在雪花表上强制分区

是否可以强制用户喜欢应用程序?