C# 使用重复的主键检测插入
My api允许尝试添加具有相同主键的实体。然而,我想过滤由于这个原因而发生的DbUpdateException,因为它们只会污染我的日志文件。C# 使用重复的主键检测插入,c#,entity-framework,C#,Entity Framework,My api允许尝试添加具有相同主键的实体。然而,我想过滤由于这个原因而发生的DbUpdateException,因为它们只会污染我的日志文件。 我在生产环境中使用Sqlite进行测试和Postgres,因此我希望有一种方法可以返回一些异常类型来获取原因。对于Sql Server,您可以使用的内部异常的属性DbUpdateException来识别主键错误的违反。对于违反主键的情况SqlException.Number=2627。 您可以尝试以下方法: try { db.SaveChang
我在生产环境中使用Sqlite进行测试和Postgres,因此我希望有一种方法可以返回一些异常类型来获取原因。对于Sql Server,您可以使用的内部异常的属性
DbUpdateException
来识别主键错误的违反。对于违反主键的情况SqlException.Number=2627
。
您可以尝试以下方法:
try
{
db.SaveChanges();
}
catch (DbUpdateException ex)
{
if (ex.InnerException is SqlException sqlEx && sqlEx.Number == 2627)
{
}
}
我认为对于
Sqlite
和Postgres
来说,关于SQL Server的想法应该是相同的,我建议过滤2601和2627以捕获主键/唯一键约束冲突:
- 2601:无法在具有唯一性的对象'%1!'中插入重复的键行 索引''%1!''。重复的键值为%ls李>
- 2627:违反了%ls约束'%1!'。无法在对象'%1!'中插入重复的键。重复的键值为%ls
try {
using(var db = new DatabaseContext()) {
db.SaveChanges();
}
}
catch(UpdateException ex) {
var sqlException = ex.InnerException as SqlException;
if(sqlException != null && sqlException.Errors.OfType<SqlError>()
.Any(se=>se.Number == 2601 || se.Number == 2627 /* primary key/unique key constraint violation */)) {
// handle duplicate
}
}
试试看{
使用(var db=new DatabaseContext()){
db.SaveChanges();
}
}
catch(UpdateException-ex){
var sqlException=ex.InnerException作为sqlException;
if(sqlException!=null&&sqlException.Errors.OfType()
.Any(se=>se.Number==2601 | | se.Number==2627/*主键/唯一键约束冲突*/){
//句柄重复
}
}
另一种方法是在插入之前检查重复项。
为此,请确保在原子事务中运行这两个操作,以避免并发问题。否则,两个或多个事务可能会尝试插入具有相同密钥的记录。我最终得到了DbUpdateException的一些扩展类,但仍然有点粗糙:
public static class UpdateExceptionHelper
{
public enum UpdateExceptionKind
{
UniqueViolation,
ForeignKeyViolation,
Unknown
}
public static UpdateExceptionKind Kind(this DbUpdateException dbUpdateException)
{
var inner = dbUpdateException.InnerException;
switch (inner)
{
case null:
return UpdateExceptionKind.Unknown;
case SqliteException sqlite:
return sqlite.Kind();
case PostgresException postgres:
return postgres.Kind();
default:
throw new Exception($"Unsupported Database Provider with Exception Type: {inner.GetType().Name}");
}
}
private static UpdateExceptionKind Kind(this PostgresException e)
{
const string UNIQUE_VIOLATION = "23505";
const string FOREIGN_KEY_VIOLATION = "23503";
switch (e.SqlState)
{
case UNIQUE_VIOLATION:
return UpdateExceptionKind.UniqueViolation;
case FOREIGN_KEY_VIOLATION:
return UpdateExceptionKind.ForeignKeyViolation;
default:
return UpdateExceptionKind.Unknown;
}
}
private static UpdateExceptionKind Kind(this SqliteException e)
{
const int SQLITE_CONSTRAINT_UNIQUE = 2067;
const int SQLITE_CONSTRAINT_PRIMARYKEY = 1555;
const int SQLITE_CONSTRAINT_FOREIGNKEY = 787;
switch (e.SqliteExtendedErrorCode)
{
case SQLITE_CONSTRAINT_PRIMARYKEY:
case SQLITE_CONSTRAINT_UNIQUE:
return UpdateExceptionKind.UniqueViolation;
case SQLITE_CONSTRAINT_FOREIGNKEY:
return UpdateExceptionKind.ForeignKeyViolation;
default:
return UpdateExceptionKind.Unknown;
}
}
}
单靠SQL server无法帮助我。我知道我可以检查内部异常。我希望有一些库可以将多个后端的异常映射到某种通用类型。在插入之前检查重复项是非常糟糕的性能。