Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用重复的主键检测插入_C#_Entity Framework - Fatal编程技术网

C# 使用重复的主键检测插入

C# 使用重复的主键检测插入,c#,entity-framework,C#,Entity Framework,My api允许尝试添加具有相同主键的实体。然而,我想过滤由于这个原因而发生的DbUpdateException,因为它们只会污染我的日志文件。 我在生产环境中使用Sqlite进行测试和Postgres,因此我希望有一种方法可以返回一些异常类型来获取原因。对于Sql Server,您可以使用的内部异常的属性DbUpdateException来识别主键错误的违反。对于违反主键的情况SqlException.Number=2627。 您可以尝试以下方法: try { db.SaveChang

My api允许尝试添加具有相同主键的实体。然而,我想过滤由于这个原因而发生的DbUpdateException,因为它们只会污染我的日志文件。
我在生产环境中使用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无法帮助我。我知道我可以检查内部异常。我希望有一些库可以将多个后端的异常映射到某种通用类型。在插入之前检查重复项是非常糟糕的性能。