You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何基于ProductID和ProductCategoryId使用LINQ生成唯一产品序列号?

优化基于ProductID和CategoryId生成唯一产品序列号的LINQ查询方案

你的问题很典型——原代码在没有匹配的产品数据时会抛出InvalidOperationException,因为空序列调用Max()是不允许的。这里有两种更健壮的LINQ方案,同时还能兼顾代码简洁性和可靠性:

方案1:使用可空类型处理空序列

通过将ID转为可空整数类型,让Max()在没有匹配项时返回null而非直接抛出异常,之后再判断是否有值来生成序列号:

public string GetProductSerialNo(int productID, int categoryId) 
{ 
    var maxId = db.AssetProductInfo
        .Where(a => a.ProductId == productID && a.CategoryId == categoryId)
        .Select(a => (int?)a.ID) // 转换为可空类型,空序列时Max()返回null
        .Max(); 
    var productSerialNo = maxId.HasValue ? maxId.Value + 1 : 1; // 无数据时从1开始
    return productSerialNo.ToString(); 
}

这种方式的优势是数据库层面的查询更高效,因为不需要额外处理默认值,仅在内存中判断是否存在最大值即可。

方案2:使用DefaultIfEmpty()设置默认值

如果更习惯直接处理非可空类型,可以用DefaultIfEmpty()给空序列设置一个默认值(比如0),之后再取最大值并加1:

public string GetProductSerialNo(int productID, int categoryId) 
{ 
    var maxId = db.AssetProductInfo
        .Where(a => a.ProductId == productID && a.CategoryId == categoryId)
        .Select(a => a.ID)
        .DefaultIfEmpty(0) // 空序列时返回包含0的单元素序列
        .Max(); 
    var productSerialNo = maxId + 1; // 无数据时0+1=1,符合预期
    return productSerialNo.ToString(); 
}

这种写法更直观,适合偏好非可空类型逻辑的场景。

重要注意事项

以上两种方案都解决了空序列的问题,但在高并发场景下仍存在重复序列号的风险——如果多个请求同时查询到相同的maxId,会生成相同的序列号。如果需要绝对保证唯一性,建议:

  • 使用数据库的事务+行级锁,在查询和插入数据时锁定对应的ProductID/CategoryId分组
  • 对于支持的数据库(如SQL Server),创建针对ProductID和CategoryId的序列对象,直接从数据库获取唯一值
  • 或者设计表结构时,将序列号作为计算列或使用自增列结合分组逻辑

内容的提问来源于stack exchange,提问作者Oyaliul Islam

火山引擎 最新活动