|
|
@ -1,4 +1,5 @@ |
|
|
using Microsoft.AspNetCore.Mvc; |
|
|
|
|
|
|
|
|
using Microsoft.AspNetCore.Hosting; |
|
|
|
|
|
using Microsoft.AspNetCore.Mvc; |
|
|
using Microsoft.AspNetCore.Mvc.Abstractions; |
|
|
using Microsoft.AspNetCore.Mvc.Abstractions; |
|
|
using Microsoft.AspNetCore.Mvc.Controllers; |
|
|
using Microsoft.AspNetCore.Mvc.Controllers; |
|
|
using Microsoft.AspNetCore.Mvc.Filters; |
|
|
using Microsoft.AspNetCore.Mvc.Filters; |
|
|
@ -15,6 +16,7 @@ using System.Threading; |
|
|
using System.Threading.Tasks; |
|
|
using System.Threading.Tasks; |
|
|
using Volo.Abp; |
|
|
using Volo.Abp; |
|
|
using Volo.Abp.Auditing; |
|
|
using Volo.Abp.Auditing; |
|
|
|
|
|
using Volo.Abp.Data; |
|
|
using Volo.Abp.Domain.Entities; |
|
|
using Volo.Abp.Domain.Entities; |
|
|
|
|
|
|
|
|
namespace Shentun.Peis |
|
|
namespace Shentun.Peis |
|
|
@ -65,6 +67,69 @@ namespace Shentun.Peis |
|
|
{ |
|
|
{ |
|
|
//errorMessage = "数据库更新错误:" + exceptionContext.Exception.Message;
|
|
|
//errorMessage = "数据库更新错误:" + exceptionContext.Exception.Message;
|
|
|
errorMessage = "数据库更新错误:" + exceptionContext.Exception.Message + "=>" + exceptionContext.Exception.InnerException.Message; |
|
|
errorMessage = "数据库更新错误:" + exceptionContext.Exception.Message + "=>" + exceptionContext.Exception.InnerException.Message; |
|
|
|
|
|
} |
|
|
|
|
|
else if (exceptionContext.Exception is AbpDbConcurrencyException concurrencyEx) |
|
|
|
|
|
{ |
|
|
|
|
|
var detailBuilder = new System.Text.StringBuilder(); |
|
|
|
|
|
detailBuilder.AppendLine("并发冲突详细信息:"); |
|
|
|
|
|
|
|
|
|
|
|
// 从内部异常获取详细信息
|
|
|
|
|
|
if (concurrencyEx.InnerException is DbUpdateConcurrencyException dbUpdateEx) |
|
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
|
|
// 获取涉及的所有实体
|
|
|
|
|
|
foreach (var entry in dbUpdateEx.Entries) |
|
|
|
|
|
{ |
|
|
|
|
|
var entity = entry.Entity; |
|
|
|
|
|
var entityType = entity.GetType().Name; |
|
|
|
|
|
var entityId = GetEntityId(entity); // 使用之前的辅助方法
|
|
|
|
|
|
|
|
|
|
|
|
detailBuilder.AppendLine($"\n▶ 冲突实体 [{entityType}]"); |
|
|
|
|
|
detailBuilder.AppendLine($" 实体ID:{entityId}"); |
|
|
|
|
|
detailBuilder.AppendLine($" 状态:{entry.State}"); |
|
|
|
|
|
|
|
|
|
|
|
// 获取数据库中的当前值
|
|
|
|
|
|
var databaseValues = entry.GetDatabaseValues(); |
|
|
|
|
|
if (databaseValues != null) |
|
|
|
|
|
{ |
|
|
|
|
|
// 记录所有发生冲突的属性
|
|
|
|
|
|
foreach (var property in entry.Properties) |
|
|
|
|
|
{ |
|
|
|
|
|
var originalValue = property.OriginalValue; |
|
|
|
|
|
var currentValue = property.CurrentValue; |
|
|
|
|
|
var databaseValue = databaseValues[property.Metadata.Name]; |
|
|
|
|
|
|
|
|
|
|
|
if (!Equals(currentValue, databaseValue)) |
|
|
|
|
|
{ |
|
|
|
|
|
detailBuilder.AppendLine($" ⚠ 字段 [{property.Metadata.Name}] 冲突:"); |
|
|
|
|
|
detailBuilder.AppendLine($" 当前值:{currentValue}"); |
|
|
|
|
|
detailBuilder.AppendLine($" 数据库值:{databaseValue}"); |
|
|
|
|
|
detailBuilder.AppendLine($" 原始值:{originalValue}"); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
detailBuilder.AppendLine($" 数据库记录可能已被删除"); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
// 如果没有内部异常,只能记录基本信息
|
|
|
|
|
|
detailBuilder.AppendLine($"异常类型:{concurrencyEx.GetType().Name}"); |
|
|
|
|
|
detailBuilder.AppendLine($"消息:{concurrencyEx.Message}"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var detailInfo = detailBuilder.ToString(); |
|
|
|
|
|
|
|
|
|
|
|
// 记录详细日志
|
|
|
|
|
|
_logger.LogWarning(concurrencyEx, "并发冲突详情:\n{Detail}", detailInfo); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
errorMessage = "数据并发,稍后再试"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
else if (exceptionContext.Exception is BusinessException) |
|
|
else if (exceptionContext.Exception is BusinessException) |
|
|
{ |
|
|
{ |
|
|
@ -158,5 +223,45 @@ namespace Shentun.Peis |
|
|
ReadException(ex.InnerException, ref error); |
|
|
ReadException(ex.InnerException, ref error); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private string GetEntityId(object entity) |
|
|
|
|
|
{ |
|
|
|
|
|
try |
|
|
|
|
|
{ |
|
|
|
|
|
// 方法1:通过实体类型获取 Id 属性
|
|
|
|
|
|
var entityType = entity.GetType(); |
|
|
|
|
|
|
|
|
|
|
|
// 查找名为 "Id" 的属性(不区分大小写)
|
|
|
|
|
|
var idProperty = entityType.GetProperty("Id") ?? |
|
|
|
|
|
entityType.GetProperty("id") ?? |
|
|
|
|
|
entityType.GetProperty("ID"); |
|
|
|
|
|
|
|
|
|
|
|
if (idProperty != null) |
|
|
|
|
|
{ |
|
|
|
|
|
var idValue = idProperty.GetValue(entity); |
|
|
|
|
|
return idValue?.ToString() ?? "null"; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 如果没找到 Id,查找可能的主键属性(以 Id 结尾)
|
|
|
|
|
|
var possibleKeys = entityType.GetProperties() |
|
|
|
|
|
.Where(p => p.Name.EndsWith("Id", StringComparison.OrdinalIgnoreCase)) |
|
|
|
|
|
.ToList(); |
|
|
|
|
|
|
|
|
|
|
|
if (possibleKeys.Any()) |
|
|
|
|
|
{ |
|
|
|
|
|
var keyValues = possibleKeys |
|
|
|
|
|
.Select(p => $"{p.Name}:{p.GetValue(entity)}") |
|
|
|
|
|
.ToList(); |
|
|
|
|
|
return string.Join(", ", keyValues); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return "未找到主键属性"; |
|
|
|
|
|
} |
|
|
|
|
|
catch (Exception ex) |
|
|
|
|
|
{ |
|
|
|
|
|
return $"获取主键失败:{ex.Message}"; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |