Files
SecMPS/api_sqlsugar/VolPro.Entity/DomainModels/device_manager/base_device.cs
T
g82tt 2315d5a174 V1.12.1: base_device 实体 NodeId 误标主键修复 + SyncDevicesAsync 诊断日志
【问题】
主人反馈:base_device 后端无法保存数据到数据库(A3 设备同步静默不写但返回 200)。

【根因】
base_device.cs:266-274 NodeId 字段被误标:
  [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
  [Key]
  public int? NodeId { get; set; }
而 DeviceId 已经是主键+自增(line 23-29),产生 3 重故障:
1. SqlSugar INSERT 时同时跳过 DeviceId 和 NodeId,但数据库 NodeId INT NULL 不是 AUTO_INCREMENT
   → entity.NodeId=gatewayNodeId 被跳过,实际写 NULL/默认值
2. Updateable WHERE 子句变成 DeviceId=X AND NodeId=Y 双重主键匹配
   → NodeId 实际值与赋的值不一致时,Update 影响行数=0 静默失败
3. SqlSugar 异常被 SyncDevicesAsync catch 块吞掉,Controller 看不到具体原因

【修复】
1. base_device.cs:268-270 移除 [SugarColumn(IsPrimaryKey=true,IsIdentity=true)] 和 [Key]
   NodeId 改为普通外键字段(只保留 Column/Editable)
2. gateway_nodesService.cs: SyncDevicesAsync 新增 INSERT try/catch + 详细日志
   - 每条新增/更新打印 Adapter/SourceId/DeviceId/NodeId 便于定位
   - 失败时记录 entity 完整字段值(Name/Cat/Grp)便于排查
   - catch 块 LogError 后 throw,异常不再被吞

【验证】
dotnet build api_sqlsugar 0 错误 0 警告

【效果】
- Insertable 正常写入 entity.NodeId=gatewayNodeId 值
- Updateable WHERE 只用 DeviceId 单主键匹配
- 异常不再静默,Controller 会返回 500 + 具体异常信息,主人能从日志看到根因
2026-07-24 05:48:18 +08:00

296 lines
8.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*如果数据库字段发生变化,请在代码生器重新生成此Model
*/
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SqlSugar;
using VolPro.Entity.SystemModels;
namespace VolPro.Entity.DomainModels
{
[Entity(TableCnName = "设备管理",TableName = "base_device",DetailTable = new Type[] { typeof(video_channel),typeof(iot_devicedata),typeof(iot_alarm)},DetailTableCnName = "视频通道,数据归档,告警记录",DBServer = "ServiceDbContext")]
public partial class base_device:ServiceEntity
{
/// <summary>
///设备ID
/// </summary>
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
[Key]
[Display(Name ="设备ID")]
[Column(TypeName="int")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public int DeviceId { get; set; }
/// <summary>
///设备名称
/// </summary>
[Display(Name ="设备名称")]
[MaxLength(100)]
[Column(TypeName="nvarchar(100)")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public string DeviceName { get; set; }
/// <summary>
///来源适配器(类型:实例)
/// </summary>
[Display(Name ="来源适配器(类型:实例)")]
[MaxLength(50)]
[Column(TypeName="nvarchar(50)")]
[Editable(true)]
public string AdapterCode { get; set; }
/// <summary>
///源系统设备ID
/// </summary>
[Display(Name ="源系统设备ID")]
[MaxLength(100)]
[Column(TypeName="nvarchar(100)")]
[Editable(true)]
public string SourceId { get; set; }
/// <summary>
///设备种类(数据字典)
/// </summary>
[Display(Name ="设备种类(数据字典)")]
[MaxLength(50)]
[Column(TypeName="nvarchar(50)")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public string DeviceCategory { get; set; }
/// <summary>
///设备分组(数据字典)
/// </summary>
[Display(Name ="设备分组(数据字典)")]
[MaxLength(20)]
[Column(TypeName="nvarchar(20)")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public string DeviceGroup { get; set; }
/// <summary>
///所属点位ID
/// </summary>
[Display(Name ="所属点位ID")]
[Column(TypeName="int")]
[Editable(true)]
public int? PointId { get; set; }
/// <summary>
///是否父设备(数据字典)
/// </summary>
[Display(Name ="是否父设备(数据字典)")]
[MaxLength(20)]
[Column(TypeName="nvarchar(20)")]
[Editable(true)]
[Required(AllowEmptyStrings=false)]
public string IsParent { get; set; }
/// <summary>
///父设备ID(自引用,子设备挂父设备下)
/// </summary>
[Display(Name ="父设备ID(自引用,子设备挂父设备下)")]
[Column(TypeName="int")]
[Editable(true)]
public int? ParentDeviceId { get; set; }
/// <summary>
///在线状态(数据字典)
/// </summary>
[Display(Name ="在线状态(数据字典)")]
[MaxLength(20)]
[Column(TypeName="nvarchar(20)")]
[Editable(true)]
public string IsOnline { get; set; }
/// <summary>
///IP地址
/// </summary>
[Display(Name ="IP地址")]
[MaxLength(50)]
[Column(TypeName="nvarchar(50)")]
[Editable(true)]
public string IpAddress { get; set; }
/// <summary>
///端口
/// </summary>
[Display(Name ="端口")]
[Column(TypeName="int")]
[Editable(true)]
public int? Port { get; set; }
/// <summary>
///安装位置
/// </summary>
[Display(Name ="安装位置")]
[MaxLength(200)]
[Column(TypeName="nvarchar(200)")]
[Editable(true)]
public string Location { get; set; }
/// <summary>
///纬度
/// </summary>
[Display(Name ="纬度")]
[Column(TypeName="double")]
[Editable(true)]
public decimal? Lat { get; set; }
/// <summary>
///经度
/// </summary>
[Display(Name ="经度")]
[Column(TypeName="double")]
[Editable(true)]
public decimal? Lng { get; set; }
/// <summary>
///三维地图模型ID
/// </summary>
[Display(Name ="三维地图模型ID")]
[MaxLength(100)]
[Column(TypeName="nvarchar(100)")]
[Editable(true)]
public string MapModelId { get; set; }
/// <summary>
///模型缩放比例
/// </summary>
[Display(Name ="模型缩放比例")]
[Column(TypeName="decimal")]
[Editable(true)]
public decimal? MapModelScale { get; set; }
/// <summary>
///模型旋转角度(JSON)
/// </summary>
[Display(Name ="模型旋转角度(JSON)")]
[MaxLength(100)]
[Column(TypeName="nvarchar(100)")]
[Editable(true)]
public string MapModelRotation { get; set; }
/// <summary>
///适配器扩展数据JSON(Owl/MC4/门禁字段均存于此)
/// </summary>
[Display(Name ="适配器扩展数据JSON(Owl/MC4/门禁字段均存于此)")]
[Column(TypeName="nvarchar(max)")]
[Editable(true)]
public string ExtraData { get; set; }
/// <summary>
///上次同步时间
/// </summary>
[Display(Name ="上次同步时间")]
[Column(TypeName="datetime")]
[Editable(true)]
public DateTime? LastSyncTime { get; set; }
/// <summary>
///启用状态(数据字典)
/// </summary>
[Display(Name ="启用状态(数据字典)")]
[MaxLength(20)]
[Column(TypeName="nvarchar(20)")]
[Editable(true)]
public string Enable { get; set; }
/// <summary>
///备注
/// </summary>
[Display(Name ="备注")]
[MaxLength(500)]
[Column(TypeName="nvarchar(500)")]
[Editable(true)]
public string Remark { get; set; }
/// <summary>
///创建人ID
/// </summary>
[Display(Name ="创建人ID")]
[Column(TypeName="int")]
[Editable(true)]
public int? CreateID { get; set; }
/// <summary>
///创建人
/// </summary>
[Display(Name ="创建人")]
[MaxLength(50)]
[Column(TypeName="nvarchar(50)")]
[Editable(true)]
public string Creator { get; set; }
/// <summary>
///创建时间
/// </summary>
[Display(Name ="创建时间")]
[Column(TypeName="datetime")]
[Editable(true)]
public DateTime? CreateDate { get; set; }
/// <summary>
///修改人ID
/// </summary>
[Display(Name ="修改人ID")]
[Column(TypeName="int")]
[Editable(true)]
public int? ModifyID { get; set; }
/// <summary>
///修改人
/// </summary>
[Display(Name ="修改人")]
[MaxLength(50)]
[Column(TypeName="nvarchar(50)")]
[Editable(true)]
public string Modifier { get; set; }
/// <summary>
///修改时间
/// </summary>
[Display(Name ="修改时间")]
[Column(TypeName="datetime")]
[Editable(true)]
public DateTime? ModifyDate { get; set; }
/// <summary>
///所属网关节点ID
/// </summary>
[Display(Name ="所属网关节点ID")]
// V1.12.1 修复:NodeId 不是主键,只是一个外键字段。
// 之前误标 [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + [Key]
// 会导致 SqlSugar INSERT 时跳过 NodeId(认为是自增)→ 数据库实际为 NULL,
// 传进来的 gatewayNodeId 永远写不进去;Update 时 WHERE 变成双主键匹配,
// 容易因 NodeId 实际值与赋的值不一致导致 Update 静默失败。
[Column(TypeName="int")]
[Editable(true)]
public int? NodeId { get; set; }
[Display(Name ="视频通道")]
[ForeignKey("DeviceId")][Navigate(NavigateType.OneToMany,nameof(DeviceId),nameof(DeviceId))]
public List<video_channel> video_channel { get; set; }
[Display(Name ="数据归档")]
[ForeignKey("DeviceId")][Navigate(NavigateType.OneToMany,nameof(DeviceId),nameof(DeviceId))]
public List<iot_devicedata> iot_devicedata { get; set; }
[Display(Name ="告警记录")]
[ForeignKey("DeviceId")][Navigate(NavigateType.OneToMany,nameof(DeviceId),nameof(DeviceId))]
public List<iot_alarm> iot_alarm { get; set; }
}
}