使用重复的主键

时间:2018-06-01 22:03:14

标签: c# entity-framework

我的api允许尝试添加具有相同主键的实体。但是我想过滤由于这个原因发生的DbUpdateException,因为那些只会污染我的日志文件。 我使用Sqlite进行测试,并在生产中使用Postgres,所以我希望有一种方法可以让我得到一些异常来获得原因。

3 个答案:

答案 0 :(得分:0)

对于Sql Server,您可以使用DbUpdateException内部异常的SqlException.Number属性来识别违反PRIMARY KEY 错误。对于违反PRIMARY KEY SqlException.Number = 2627。 你可以尝试这样的事情:

try
{
    db.SaveChanges();
}
catch (DbUpdateException ex)
{
    if (ex.InnerException is SqlException sqlEx && sqlEx.Number == 2627)
    {
    }
}

我相信SqlitePostgres这个想法应该是相同的

答案 1 :(得分:0)

关于SQL Server,我建议过滤SqlException.Number 2601和2627以捕获主键/唯一键约束违规:

  • 2601:无法在对象'%。* ls'中插入具有唯一的重复键行 index'%。* ls'。重复键值为%ls。
  • 2627:违反%ls约束'%。* ls'。无法在对象'%。* ls'中插入重复键。重复键值为%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
    }
}

另一种方法是在插入之前检查重复项 为此,请确保在原子事务中运行这两个操作以避免并发问题。否则,两个或多个事务可能会尝试插入具有相同密钥的记录。

答案 2 :(得分:0)

我最终得到了一些DbUpdateException的扩展类仍然有点hacky:

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;
        }
    }
}