【问题标题】:SqLite Auto-increment for one its Composite Keys其复合键之一的 SqlLite 自动增量
【发布时间】:2018-12-05 19:40:35
【问题描述】:

以下列在 SQL Server IDENTITY(1,1) 中设置为自动递增,我希望在 SqlLite 上具有类似的行为:Tenant.TenantID、Project.ProjectID 和 Credits .CreditsID。虽然 Sqlite 中有AUTOINCREMENT,我也试过了,但它只适用于只有 1 个主键的表。我尝试了以下测试:

顺便说一句,我使用Microsoft.EntityFrameworkCore.Sqlite 2.1.4 进行此测试

为这些设置为自动递增的列显式赋值:

  1. Tenant.TenantID

    一个。 -99 : 保存后保持 -99

    b. 0:保存后变为1

    c. 99 : 保存后仍为 99

  2. 对于Project.ProjectID & Credits.CreditsID

    一个。将更改保存到 DbContext 后,-99 和 99 值保持不变。但我不想明确分配这些值,因为我的 DbContext 中有一堆测试数据。

    b.分配显式值 0 会引发此错误:Microsoft.Data.Sqlite.SqliteException : SQLite Error 19: 'NOT NULL constraint failed: Credits.CreditsID'.

我真的很感激能帮助我解决这个问题的人。这已经困扰我好几天了。

【问题讨论】:

  • 旁注:我不会将 TenantID 作为 Project 主键的一部分,也不会将 ProjectID 和 TenantID 作为 Credit 主键的一部分。每个表只有一个 PK 列和父级的一个外键(即在 Credit 中根本没有 TenantID)。如果您必须更改参考,它将使数据管理更加容易。
  • 虽然我可能同意你的计划,因为这是我通常的数据库设计方式,但对于这个项目,数据库设计师之所以这样,是因为他计划对这个进行分区。

标签: c# .net entity-framework sqlite testing


【解决方案1】:

对于 SQLite,您可能不想使用 AUTOINCREMENT,这实际上并没有将列设置为递增,而是设置了一个约束,即如果没有明确设置,则该值必须是比已分配的值更高的值。

如果没有显式设置值,只需使用 INTEGER PRIMARY KEY 定义列即可将列设置为递增。注意每个表只能有一个这样的列。

  • 请注意,SQLite 不保证递增 1,而是保证唯一标识符是一个整数,甚至可能更小(仅在 9223372036854775807 的 id 被分配之后)。SQLite Autoincrement。在这种情况下,使用 AUTOINCREMENT 将失败并出现 SQLite Full 异常,而没有 AUTOINCREMENT SQLite 将尝试查找未使用的 id。

查看您的图表,我相信 Credits 表不需要 TennantID,因为这可以通过引用 Tennant 的项目获得。

忽略构成关系的列以外的其他列(还添加将强制引用完整性的可选外键限制),那么我相信您可以使用以下内容:-

DROP TABLE IF EXISTS credits;
DROP TABLE IF EXISTS project;
DROP TABLE IF EXISTS tennant;
CREATE TABLE IF NOT EXISTS tennant (tennant_id INTEGER PRIMARY KEY, Name TEXT, other_columns);
CREATE TABLE IF NOT EXISTS project (project_id INTEGER PRIMARY KEY, tennant_reference REFERENCES tennant(tennant_id), Title);
CREATE TABLE IF NOT EXISTS credits (credit_id INTEGER PRIMARY KEY, project_reference INTEGER REFERENCES project(project_id), other_columns TEXT);
CREATE TABLE IF NOT EXISTS creidts (credit_id INTEGER PRIMARY KEY, project_reference INTEGER, other_columns);
INSERT INTO tennant VALUES(1,'Fred','other data'); -- Explicit ID 1
INSERT INTO tennant (Name,other_columns) VALUES('Mary','Mary''s other data'),('Anne','Anne''s other data'); -- Implicit ID 's (2 and 3 most likely)
INSERT INTO project VALUES (99,1,'Project001 for Fred'); --  Explicit Project ID 99 - tennant 1 = Fred
INSERT INTO project (tennant_reference,Title) VALUES(1,'Project002 for Fred'),(2,'Project003 for Mary'),(3,'Project004 for Anne'); -- 3 implicit project id's 100,101 and 102 (most likely)

-- Result 1
SELECT * FROM project JOIN tennant ON tennant_reference = tennant.tennant_id;

INSERT INTO credits VALUES(199,99,'Other credit columns'); -- Explicit credit ID of 199 for Project001 (tennant implied) 
INSERT INTO credits VALUES(0,99,'Other credit colums credit_id = 0'); -- Explicit credit ID of 0 for Project002
INSERT INTO credits (project_reference,other_columns) VALUES (100,'for Project002'),(100,'another for Project002'),(102,'for Project004');

SELECT * FROM credits JOIN project ON project_reference = project_id JOIN tennant ON tennant_reference = tennant_id;
  • 这会删除所有现有表以简化测试。
  • 然后创建了 3 个表。
  • 行被显式和隐式(推荐的方式)插入到 Tennant 表中,然后插入到 Project 表中(请注意,由于外键约束,引用不存在的租户的行不能插入到 Project 表中)
  • 然后列出项目以及加入的租户详细信息(请参阅结果)
  • 然后使用显式和隐式信用 ID 将行插入信用表(请注意,199 是显式定义的,然后是 0)。
  • 如您所见,自动生成 ID 时,它们通常比迄今为止使用的最大值大 1。

结果

第一个查询(带有相关 Tennant 的项目)

与相关项目和底层相关 Tennant 的第二次查询积分

【讨论】:

  • 哇!非常感谢您的解释。虽然这很有帮助,但我对设计几乎没有控制权——我会这样说。对于这个项目,数据库设计者之所以这样,是因为他计划对此进行分区。
猜你喜欢
  • 2012-08-11
  • 2014-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-27
  • 2016-11-11
  • 1970-01-01
相关资源
最近更新 更多