☰
.NETCore SqlSuagr 根据 mysql 数据表按顺序生成简单编号
2026/10/25 1:44:49 网站建设 项目流程

目录

场景一:全局唯一序列号(Sequence)

方案 A:利用 MySQL 的 AUTO_INCREMENT 属性(推荐)

方案 B:使用专门的 Sequence 表(模拟 Oracle Sequence)

场景二:基于已有数据生成新的顺序编号

方案 A:使用 MySQL 的 ROW_NUMBER() 和 PARTITION BY (推荐)

方案 B:在应用程序中生成(不推荐,除非数据量极小)

SqlSugar 针对 MySQL 的一些实用技巧

总结


如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

在 .NET 8 中使用SqlSugarORM 根据 MySQL 数据表按顺序生成编号,SqlSugar在某些方面提供了更简洁的语法糖,尤其是在执行原生 SQL 和模拟数据库函数方面。

以下是针对前面提到的两种场景,使用SqlSugar的实现方式:


场景一:全局唯一序列号(Sequence)

SqlSugar同样推荐使用 MySQL 的AUTO_INCREMENT属性。

方案 A:利用 MySQL 的AUTO_INCREMENT属性(推荐)

1. MySQL 建表语句:

CREATE TABLE YourTable (
Id INT AUTO_INCREMENT PRIMARY KEY,
Column1 VARCHAR(255),
Column2 INT
);

2.SqlSugar实体类:

public class YourTable
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)] // IsIdentity = true 对应 AUTO_INCREMENT
public int Id { get; set; }
public string Column1 { get; set; }
public int Column2 { get; set; }
}

3.SqlSugar插入数据:

SqlSugar在插入时会自动处理IsIdentity = true的列,无需手动干预。

// 假设 dbContext 是你的 SqlSugarClient 实例
var dbContext = new SugarClient(); // ... 初始化你的 SqlSugarClient

var newItem = new YourTable
{
Column1 = "Some Value",
Column2 = 123
};

// Insertable().ExecuteCommandAsync() 会返回插入的行数
int rowsAffected = await dbContext.Insertable(newItem).ExecuteCommandAsync();

if (rowsAffected > 0)
{
// newItem.Id 现在已经包含了数据库生成的自增 ID
Console.WriteLine($"Generated ID: {newItem.Id}");
}

优点:

  • 最简单、性能最高,由数据库原生支持。
  • SqlSugar对AUTO_INCREMENT的支持非常完善。
方案 B:使用专门的 Sequence 表(模拟 Oracle Sequence)

SqlSugar同样支持模拟 Sequence。

1. MySQL 建表语句(Sequence 表):

CREATE TABLE Sequences (
SequenceName VARCHAR(100) PRIMARY KEY,
CurrentValue BIGINT NOT NULL,
IncrementBy INT DEFAULT 1
);

INSERT INTO Sequences (SequenceName, CurrentValue, IncrementBy)
VALUES ('YourTableIdSeq', 0, 1);

2.SqlSugar实体类:

public class Sequence
{
[SugarColumn(IsPrimaryKey = true)]
public string SequenceName { get; set; }
public long CurrentValue { get; set; }
public int IncrementBy { get; set; }
}

3.SqlSugar获取序列值并插入数据:

SqlSugar提供了更直接的执行 SQL 语句的方法,并且可以通过ExecuteCommandAsync获取影响行数。

public class SequenceService
{
private readonly ISugarQueryable _dbContext;

public SequenceService(ISugarQueryable dbContext)
{
_dbContext = dbContext;
}

// 推荐使用事务来保证原子性
public async Task<long> GetNextSequenceValue(string sequenceName, SugarTransactionApi transaction = null)
{
// 1. 获取序列当前值
var sequence = await _dbContext.Queryable<Sequence>()
.SingleAsync(s => s.SequenceName == sequenceName);
if (sequence == null)
{
throw new Exception($"Sequence '{sequenceName}' not found.");
}

long nextValue = sequence.CurrentValue + sequence.IncrementBy;

// 2. 更新序列值
sequence.CurrentValue = nextValue;
// 标记为已修改,以便 EF Core/SqlSugar 知道需要更新
_dbContext.Updateable(sequence).ExecuteCommandAsync();

return nextValue;
}

// 提供一个带有事务的重载
public async Task<long> GetNextSequenceValue(string sequenceName, SugarTransactionApi transaction)
{
// 1. 获取序列当前值
var sequence = await transaction.Queryable<Sequence>()
.SingleAsync(s => s.SequenceName == sequenceName);
if (sequence == null)
{
throw new Exception($"Sequence '{sequenceName}' not found.");
}

long nextValue = sequence.CurrentValue + sequence.IncrementBy;

// 2. 更新序列值
sequence.CurrentValue = nextValue;
transaction.Updateable(sequence).ExecuteCommand(); // 在事务中更新

return nextValue;
}
}

4. .NET Core 插入数据时的调用:

using (var db = new SugarClient()) // 你的 SqlSugarClient
{
// 开启事务
await db.Ado.BeginTransactionAsync();
try
{
var sequenceService = new SequenceService(db); // 传递 ISugarQueryable
// 使用带有事务的重载
long newId = await sequenceService.GetNextSequenceValue("YourTableIdSeq", db.Ado.SugarTransaction);

var newItem = new YourTable
{
Id = (int)newId, // 假设 Id 列是 int
Column1 = "Sequence Value",
Column2 = 456
};

await db.Insertable(newItem).ExecuteCommandAsync();

// 提交事务
await db.Ado.CommitTranAsync();

Console.WriteLine($"Generated ID: {newId}");
}
catch (Exception ex)
{
// 回滚事务
await db.Ado.RollbackTranAsync();
Console.WriteLine($"Error: {ex.Message}");
}
}

优点:

  • SqlSugar的 API 简洁,事务管理直观。

缺点:

  • 性能相对AUTO_INCREMENT较低。

场景二:基于已有数据生成新的顺序编号

SqlSugar在处理原生 SQL 和窗口函数方面非常强大。

方案 A:使用 MySQL 的ROW_NUMBER()和PARTITION BY(推荐)

1. MySQL 查询语句:

SELECT
t.*,
ROW_NUMBER() OVER (PARTITION BY t.Category ORDER BY t.CreatedAt ASC) AS SequentialNumber
FROM
YourTable t;

2.SqlSugar查询:

SqlSugar提供了Queryable()扩展,可以直接调用原生 SQL,并且可以方便地映射到实体。

public class YourTable
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
public string Column1 { get; set; }
public int Column2 { get; set; }
public string Category { get; set; }
public DateTime CreatedAt { get; set; }

// 注意:这里不要直接定义 SequentialNumber 属性,除非你确保数据库表也这么设计了
// 如果只是查询时生成,可以在返回结果时映射。
}

// ... 在你的 Service 或 Controller 中 ...

public async Task<List<YourTable>> GetItemsWithSequentialNumber(string category)
{
var dbContext = new SugarClient(); // 你的 SqlSugarClient

var rawSql = $@"
SELECT
t.*,
ROW_NUMBER() OVER (PARTITION BY t.Category ORDER BY t.CreatedAt ASC) AS SequentialNumber
FROM
YourTable t
WHERE t.Category = '{category}' -- 注意:此处使用字符串拼接,如果category来自用户输入,需要做SQL注入防御!
";
// 更安全的方式:使用参数化查询
// var rawSql = @"
// SELECT
// t.*,
// ROW_NUMBER() OVER (PARTITION BY t.Category ORDER BY t.CreatedAt ASC) AS SequentialNumber
// FROM
// YourTable t
// WHERE t.Category = @Category
// ";
// var items = await dbContext.SqlQueryable<YourTable>(rawSql)
// .AddParameters(new { Category = category })
// .ToListAsync();

// 如果 SequentialNumber 不是数据库字段,而只是查询的别名,
// 你可能需要创建一个临时的DTO类来接收结果,或者直接从 SqlSugarResult 中解析。
// 简单起见,假设 YourTable 暂时不需要 SequentialNumber 属性,我们直接查询并用 SqlSugarResult 解析

var resultList = await dbContext.Ado.SqlQueryable<dynamic>(rawSql).ToListAsync(); // 使用dynamic接收

// 将 dynamic 结果转换为 List<YourTable> 并添加 SequentialNumber
var finalResult = new List<YourTable>();
foreach (var row in resultList)
{
var item = new YourTable
{
Id = (int)row.Id,
Column1 = row.Column1,
Column2 = (int)row.Column2,
Category = row.Category,
CreatedAt = (DateTime)row.CreatedAt
// 无法直接映射到 YourTable 的 SequentialNumber 属性,因为这个属性只在查询结果中存在
};
// 如果你需要这个值,可以创建一个DTO
// finalResult.Add(new YourTableDto { ..., SequentialNumber = (int)row.SequentialNumber });

// 简单演示,直接用动态对象打印
Console.WriteLine($"ID: {row.Id}, Category: {row.Category}, SeqNum: {(int)row.SequentialNumber}");

// 如果真的需要为 YourTable 实体添加一个属性,并在内存中填充:
// var mappedItem = dbContext.Mapping<YourTable>().Map(item, row); // 假设 SqlSugar有此方法
// mappedItem.SequentialNumber = (int)row.SequentialNumber; // 手动赋值
// finalResult.Add(mappedItem);
}

return finalResult; // 返回你的DTO或处理过的实体列表
}

注意:SqlSugar在SqlQueryable返回时,可以直接映射到实体属性。如果你的实体类中没有SequentialNumber属性,则需要创建 DTO。如果实体类中暂时没有该属性,但你想在查询时生成并读取,可能需要一个临时 DTO 或者直接使用dynamic。

方案 B:在应用程序中生成(不推荐,除非数据量极小)

SqlSugar同样可以通过 LINQ 语法在内存中生成。

public async Task<List<YourTable>> AddSequentialNumbersInMemory(List<YourTable> items)
{
var groupedItems = items
.GroupBy(item => item.Category)
.Select(group => group.OrderBy(item => item.CreatedAt).ToList())
.SelectMany(list => list)
.ToList();

int currentNumber = 1;
string currentCategory = null;

foreach (var item in groupedItems)
{
if (currentCategory == null || item.Category != currentCategory)
{
currentCategory = item.Category;
currentNumber = 1;
}
else
{
currentNumber++;
}
// 假设 YourTable 有 SequentialNumber 属性
// item.SequentialNumber = currentNumber;
Console.WriteLine($"Item ID: {item.Id}, Category: {item.Category}, SeqNum: {currentNumber}");
}

return items;
}

// 调用示例
// var db = new SugarClient();
// var allItems = await db.Queryable<YourTable>().ToListAsync();
// await AddSequentialNumbersInMemory(allItems);
// // 如果需要更新回数据库,需要进行后续的 Updateable 操作


SqlSugar针对 MySQL 的一些实用技巧

  1. 获取最新插入 ID:
    • dbContext.Insertable(obj).ExecuteReturnIdentity();会直接返回插入对象的主键 ID。
    • dbContext.Insertable(obj).ExecuteCommand();返回影响行数,ID 会自动填充到obj对象中。
  2. 事务管理:
    • await db.Ado.BeginTransactionAsync();
    • await db.Ado.CommitTranAsync();
    • await db.Ado.RollbackTranAsync();
    • 在事务中执行操作时,需要将SugarTransactionApi传递给Insertable、Updateable等方法,或者直接使用db.Ado.SugarTransaction属性。
  3. 原生 SQL 执行:
    • dbContext.Ado.SqlQueryable<T>(sql).AddParameters(parameters).ToList();是执行复杂 SQL 的利器。

总结

  • 全局序列号:优先使用AUTO_INCREMENT,SqlSugar的IsIdentity = true属性支持良好。如果需要模拟 Sequence,请务必在事务中操作,并理解其性能开销。
  • 生成顺序编号:
    • 查询时动态生成:强烈建议使用 MySQL 的ROW_NUMBER()窗口函数,通过SqlQueryable执行,并使用dynamic或 DTO 来接收结果。
    • 插入/更新时固定编号:需要先查询出当前最大的序号,再执行插入/更新。务必在事务中完成。

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询