C#从SQL外键表查询PC数据遇类型转换错误及品牌型号获取问题
PC数据查询异常修正方案
问题背景
搭建首个学习应用时,需要从PC表及关联的外键表(存储ID与对应名称)中获取数据,目标是显示PC的品牌、型号等名称而非ID。目前已能获取PC表基础数据,但出现System.InvalidCastException: 'Specified cast is not valid.'错误,且无法正确显示外键表的名称信息。
数据库表结构说明:
- PC表包含
PC_ID、PC_SERIAL、PC_NAME、PC_BRAND_ID、PC_MODEL_ID等外键ID字段 - 关联表包括
PC_BRAND(PC_BRAND_ID、PC_BRAND)、PC_MODEL(PC_MODEL_ID、PC_MODEL)、PC_NET(PC_NET_ID、PC_NET)、PC_OS(PC_OS_ID、PC_OS)、PC_RAM(PC_RAM_ID、PC_RAM),每个关联表均为ID+名称的结构
错误原因
- SQL查询列与转换逻辑不匹配:SQL仅返回了名称字段,但转换代码试图将这些字符串类型的名称列强制转换为int类型的外键ID,同时列索引越界(SQL返回7列,转换代码取到第8个索引)
- 模型定义错误:PC类中
PC_Model的类型错误定义为PCBrand,而非对应的PCModel类 - 导航属性未实例化:转换代码仅赋值了外键ID,未实例化
PC_Brand、PC_Model等导航属性,导致ToString无法显示名称
修正步骤
1. 修正SQL查询语句
需要同时返回外键ID和对应的名称字段,确保后续能正确映射导航属性:
private const string SqlGetAllPC = @"Select PC.PC_ID, PC.PC_NAME, PC.PC_SERIAL, PC.PC_BRAND_ID, PC_BRAND.PC_BRAND, PC.PC_MODEL_ID, PC_MODEL.PC_MODEL, PC.PC_NET_ID, PC_NET.PC_NET, PC.PC_OS_ID, PC_OS.PC_OS, PC.PC_RAM_ID, PC_RAM.PC_RAM FROM PC INNER JOIN PC_BRAND on PC.PC_BRAND_ID=PC_BRAND.PC_BRAND_ID INNER JOIN PC_MODEL ON PC.PC_MODEL_ID=PC_MODEL.PC_MODEL_ID INNER JOIN PC_NET ON PC.PC_NET_ID=PC_NET.PC_NET_ID INNER JOIN PC_OS ON PC.PC_OS_ID=PC_OS.PC_OS_ID INNER JOIN PC_RAM ON PC.PC_RAM_ID=PC_RAM.PC_RAM_ID";
2. 修正PC模型定义
将PC_Model的类型改为正确的PCModel:
public class PC { public int PC_ID { get; set; } public string PC_SERIAL { get; set; } public string PC_NAME { get; set; } public Nullable<int> PC_BRAND_ID { get; set; } public PCBrand PC_Brand { get; set; } public Nullable<int> PC_MODEL_ID { get; set; } public PCModel PC_Model { get; set; } // 修正类型为PCModel public Nullable<int> PC_OS_ID { get; set; } public PCOS PC_OS { get; set; } public Nullable<int> PC_NET_ID { get; set; } public PCNet PC_Net { get; set; } public Nullable<int> PC_RAM_ID { get; set; } public PCRam PC_Ram { get; set; } public override string ToString() { return $"{PC_ID} - {PC_NAME} - {PC_SERIAL} - {PC_Model} - {PC_Brand} - {PC_OS} - {PC_Net} - {PC_Ram}"; } }
3. 给外键类添加ToString方法
确保PC的ToString能正确显示名称而非类名:
namespace Inventory.Data.Model { public class PCBrand { public int PC_BRAND_ID { get; set; } public string PC_BRAND { get; set; } public override string ToString() { return PC_BRAND; } } public class PCModel { public int PC_MODEL_ID { get; set; } public string PC_MODEL { get; set; } public override string ToString() { return PC_MODEL; } } public class PCNet { public int PC_NET_ID { get; set; } public string PC_NET { get; set; } public override string ToString() { return PC_NET; } } public class PCOS { public int PC_OS_ID { get; set; } public string PC_OS { get; set; } public override string ToString() { return PC_OS; } } public class PCRam { public int PC_RAM_ID { get; set; } public string PC_RAM { get; set; } public override string ToString() { return PC_RAM; } } }
4. 修正数据转换方法
在ConvertToPC中实例化导航属性,并正确映射SQL返回的列:
private IEnumerable<PC> ConvertToPC(DataTable data) { List<PC> tmp = new List<PC>(); foreach (DataRow row in data.Rows) { tmp.Add(new PC() { PC_ID = row.Field<int>(0), PC_NAME = row.Field<string>(1), PC_SERIAL = row.Field<string>(2), PC_BRAND_ID = row.Field<int?>(3), PC_Brand = new PCBrand() { PC_BRAND_ID = row.Field<int>(3), PC_BRAND = row.Field<string>(4) }, PC_MODEL_ID = row.Field<int?>(5), PC_Model = new PCModel() { PC_MODEL_ID = row.Field<int>(5), PC_MODEL = row.Field<string>(6) }, PC_NET_ID = row.Field<int?>(7), PC_Net = new PCNet() { PC_NET_ID = row.Field<int>(7), PC_NET = row.Field<string>(8) }, PC_OS_ID = row.Field<int?>(9), PC_OS = new PCOS() { PC_OS_ID = row.Field<int>(9), PC_OS = row.Field<string>(10) }, PC_RAM_ID = row.Field<int?>(11), PC_Ram = new PCRam() { PC_RAM_ID = row.Field<int>(11), PC_RAM = row.Field<string>(12) } }); } return tmp; }
验证
修改完成后,点击按钮执行查询,即可在弹窗中看到包含品牌、型号等名称的PC信息,同时System.InvalidCastException错误会被解决。
内容的提问来源于stack exchange,提问作者xAndrula
相关产品推荐
相关产品推荐

