【问题标题】:How can I retrieve data from a foreign key table in SQL with C#如何使用 C# 从 SQL 中的外键表中检索数据
【发布时间】:2023-01-29 21:00:10
【问题描述】:

我正在尝试构建我的第一个用于学习目的的应用程序,但我遇到了困难。

我的目标是从一个标有 PC 的表和几个具有 ID 和字符串值的外键表中检索数据。我能够执行一个 SQL 查询,从 PC 表中检索所有信息(包括外键 ID),但我希望能够看到 pc 的“品牌”和“型号”。

这是我得到的错误:

System.InvalidCastException:“指定的转换无效。”

我在 C# 中的 PC 模型如下所示:

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 PCBrand PC_Model { get; set; }
    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}";
    }
}

例如,我的一个外键表如下所示:

namespace Inventory.Data.Model
{
    public class PCBrand
    {
        public int PC_BRAND_ID { get; set; }
        public string PC_BRAND { get; set; }
    }
}

这是我的存储库类中的代码:

private const string SqlGetAllPC = @"Select PC.PC_ID, PC.PC_NAME,
     PC_BRAND.PC_BRAND,PC_MODEL.PC_MODEL,PC_NET.
     PC_NET,PC_OS.PC_OS,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";

    public IEnumerable<PC> GetAllFromPc()
    {
        IEnumerable<PC> list = null;

        try
        {
            connector.OpenConnection();
            System.Data.DataTable data = connector.GetData(SqlGetAllPC);

            if (data != null && data.Rows.Count > 0)
            {
                list = ConvertToPC(data);
            }
        }
        catch (Exception)
        {
            throw;
        }
        finally
        {
            connector.CloseConnection();
        }

        return list;
    }

    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_SERIAL = row.Field<string>(1),
                PC_NAME = row.Field<string>(2),
                PC_BRAND_ID = row.Field<int>(3),
                PC_MODEL_ID = row.Field<int>(4),
                PC_OS_ID = row.Field<int>(5),
                PC_NET_ID = row.Field<int>(6),
                PC_RAM_ID = row.Field<int>(7),
            });
        }

        return tmp;
    }
}

最后是我检索数据的按钮

private void GetAllButton(object sender, RoutedEventArgs e)
{
   Data.Repositories.PCRepository newpc = new Data.Repositories.PCRepository();

   IEnumerable<Data.Model.PC> data = newpc.GetAllFromPc();

   if (data != null)
   {
       StringBuilder sb = new StringBuilder();
       data.ToList()
           .ForEach(x=> sb.AppendLine(x.ToString()))
       MessageBox.Show(sb.ToString());
   }
}

通过一些编辑,我能够从我的 PC 表中检索。但我还想从数据库中的PC_BrandPC_Model 表中检索 PC 的型号/品牌名称:

【问题讨论】:

  • 代码中的哪一行抛出异常?
  • 我推荐小巧玲珑。我会忘记你那里有什么并开始使用它,因为它会使数据库访问更简单。
  • @Chetan 它看起来像 PCRepository 中的 tmp.Add(new PC()
  • 当您正在读取的数据与您的视图模型或模型使用不匹配时,您还应该定义纯粹用于数据访问的 dto 类。
  • @Andy 感谢您的建议。它可能更简单,但我的“导师”告诉我,我应该尝试看看我是否可以以这种方式工作......

标签: c# sql wpf


【解决方案1】:

您的SELECT 正在读取我认为是字符串值的内容(PC_MODEL.PC_MODEL、PC_NET.PC_NET、PC_OS.PC_OS、PC_RAM.PC_RAM),但您将它们分配给整数,因此转换无效。

为什么我确定这些是字符串?因为你的加入。您正在加入例如PC_MODEL_ID 几乎肯定是整数。

将您的SELECT 更改为:

SELECT PC.PC_ID, PC.PC_NAME, PC_BRAND.PC_BRAND,PC.PC_MODEL_ID, PC.PC_NET_ID, PC.PC_OS_ID,PC.PC_RAM_ID
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

请注意,如果您只选择整数值,则不需要所有其他联接。

编辑

您需要将选择更改为

SELECT PC.PC_ID, PC.PC_SERIAL, PC.PC_NAME, 
PC_BRAND.PC_BRAND, PC.PC_BRAND_ID, 
PC_MODEL.PC_MODEL, PC.PC_MODEL_ID, 
PC_NET.PC_NET, PC.PC_NET_ID, 
PC_OS.PC_OS, PC.PC_OS_ID, 
PC_RAM.PC_RAM, PC.PC_RAM_ID 
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

现在您可以在 ConvertToPC 中执行类似的操作:

private static 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_SERIAL = row.Field<string>(1),
            PC_NAME = row.Field<string>(2),
            PC_Brand = new PCBrand
            {
                PC_BRAND = row.Field<string>(3),
                PC_BRAND_ID = row.Field<int>(4)
            },
            PC_BRAND_ID = row.Field<int>(4),
            PC_Model = new PCModel
            {
                PC_MODEL = row.Field<string>(5),
                PC_MODEL_ID = row.Field<int>(6)
            },
            PC_MODEL_ID = row.Field<int>(6),
            PC_Net = new PCNet
            {
                PC_NET = row.Field<string>(7),
                PC_NET_ID = row.Field<int>(8)
            },
            PC_NET_ID = row.Field<int>(8),
            PC_OS = new PCOS
            {
                PC_OS = row.Field<string>(9),
                PC_OS_ID = row.Field<int>(10)
            },
            PC_OS_ID = row.Field<int>(10),
            PC_Ram = new PCRam
            {
                PC_RAM = row.Field<string>(11),
                PC_RAM_ID = row.Field<int>(12)
            },
            PC_RAM_ID = row.Field<int>(12)
        });
    }
    return tmp;
}

请注意,我已尽可能少地更改您的代码。在实践中,我会做很多不同的事情。例如,现在所有外键 ID 都是重复的:您的 PC 类中不再有 PCModel 类型的对象和 int PC_MODEL_ID,您只需要对象 PCModel,因为它已经包含 ID。

【讨论】:

  • 嗨乔纳森!感谢您花时间回答。我更新了我的问题,最后你可以看到我做了什么来从 PC 表中获取所有信息。不过,我希望能够从外键表中获取信息。喜欢 PC 的品牌或型号。关于如何做到这一点的任何提示?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-09-25
  • 2014-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-05
相关资源
最近更新 更多