【问题标题】:Create Strongly Typed Dataset for a stored procedure that return more than one table为返回多个表的存储过程创建强类型数据集
【发布时间】:2019-06-20 12:05:09
【问题描述】:

我有一个执行 3 选择的存储过程。如何创建可以访问所有 3 个表并读取数据的强类型数据集。默认情况下,Visual Studio 会生成一个仅包含第一个表的数据集

我已经尝试过使用 Visual Studio Typed Dataset 来拖放存储过程。

存储过程是这样的:

Create Procedure GetData
As
Begin
Select ColA, ColB, ColC from TableA
Select ColD, ColE, ColF from TableB
Select ColG, ColH, ColI from TableC
End

【问题讨论】:

  • Dataset 对象有一个属性Tables,它是DataTables 的集合,其中应该有3 个项目(您的3 个表来自选择)。请发布您的存储过程以及预期结果和您当前得到的结果。
  • 这可能是不可能的;一个普通的数据适配器会在遇到多个选择时为每个强类型数据集创建一个表,但是强类型的数据集表具有名称 - 并且不一定从 SELECT * FROM a JOIN B USING c 返回的一件事是名称;那么 ST 数据集的 tableadaoter 如何知道将这些数据放入 FooBarTable 中?
  • @CaiusJard 他总是可以为每个 Select 添加一个名为 Table Name 的列,然后根据该列从属性集合中选择正确的表 Tables 至少我就是这样过去做过。
  • 这个 Q 是专门关于强类型数据集的可视化设计,并使用 msdatasetgenerator.exe 从 xml 转换为一组存根类
  • @CaiusJard 然后在xml中添加一个名为Table Name的节点

标签: c# database dataset strongly-typed-dataset


【解决方案1】:

如果您迫切需要这样做,我认为您不会使用纯强类型设计器生成的解决方案取得成功; tableadapter 旨在在 db 数据(您的强类型数据表)的本地数据表表示和返回行的数据库查询之间进行调解。 tableadapter 中的“表”与数据表相关,而不是数据库表。

单个 tableadapter 不打算充当 3 个本地数据表和提供 3 个数据库查询输出的远程过程之间的中介。主要是它不能这样做,因为客户端代码没有任何东西可以用来识别,对于你的 sql ......

Select ColA, ColB, ColC from TableA
Select ColD, ColE, ColF from TableB
Select ColG, ColH, ColI from TableC

...select * from TableA 的结果应该进入数据集中的 TableADataTable 等。数据来自 tableA 的事实在通过线路传输时丢失了,因为它完全不相关,甚至可能不是真的。

当 tableadapter 与单个 select 一起正确使用时,它会隐式知道结果应该放入的数据表。TableADataTable 具有相应的 TableATableAdapter,TableATableAdapter 从数据库中的某个位置选择数据并将其存储在 TableADataTable 中 - 有数据集中没有其他表被 TableATableAdapter 设计用于操作,因此它在运行查询后不需要任何关于数据块去向的提示。 TableATableAdapter 甚至可以加载一个根本不从数据库 TableA 返回任何数据的查询;只要它运行的查询产生一组正确的数字和类型的列,该数据就会进入 TableADataTable,因为这是 TableATableAdapter 硬编码要做的。它不服务于其他数据表,并且对任何其他数据表不感兴趣。

因为您的存储过程无法向 tableadapter 指示哪些结果集应该存储在哪个表中,所以您设想的解决方案无法工作。

简单的规则是:“一只狗,一个完成” - “一个db查询结果集,一个tableadapter,一个强类型数据表”

因此,我强烈建议您按预期使用这些东西:

  • 为TableA、TableB和TableC创建3个tableadapter和对应的数据表
  • 在您的代码中分别填写:

var ds = new StronglyTypedDataSet();
var ata as new TableATableAdapter();
ata.Fill(ds);
var bta as new TableBTableAdapter();
bta.Fill(ds);
var cta as new TableCTableAdapter();
cta.Fill(ds);

“我们希望避免对单个页面进行多次 db 调用”并没有真正的意义——这听起来像是您想象中的问题的解决方案,而不是真正会发生的问题。尝试一次执行这些操作而不是 3 次执行这些操作几乎没有性能优势。您可能不同意,但请测试一下 - 不要只是凭直觉。连接被池化,语句被缓存和准备,如果你真的认为它会有很大帮助的话,可以同时执行 3 个语句。

归根结底,如果您有 9 兆字节的数据要从数据库中提取,那么每次提取 3 mb 的数据与提取 9 的数据的 1 次之间的差异将是微乎其微的;您没有等待 30 秒打开连接,每秒读取 3 mb,等待另外 30 秒关闭它,广告必须重新完成(总时间 183 秒)并且所有瓶颈都归因于连接管理.即使您确实有一个超级延迟连接,需要 30 秒来传输 SELECT 并需要另外 30 秒来开始读取数据,您也可以同时启动 3 个请求,并且根据定义它需要相同的时间来发送3 个 SELECT 将调用 1 个过程调用(都需要 61 秒)


如果您不同意尝试将所有操作合二为一的原因是虚假的,那么您可能希望继续尝试通过您选择的方法进行操作,在这种情况下,我认为您将不得不选择:

使用标准的数据适配器和数据集

然后将数据移动到类型集以使用它

SqlConnection con = new SqlConnection("YourConnection String");
SqlDataAdapter da = new SqlDataAdapter();
DataSet ds = new DataSet();
SqlCommand cmd = new SqlCommand("storedprocedure", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@p1", whatever); //if you have parameters.
SqlDataAdapter da= new SqlDataAdapter(cmd);
da.Fill(ds);
con.Close();

现在您有一个包含 3 个表的数据集,您的问题是找出哪个表是哪个表。假设 ds.Tables[0] 用于 TableA:

foreach(var ro in ds.Tables[0].Rows)
  typedDs.TableA.AddTableARow(ro.ItemArray);

对 b 和 c 表重复此操作

将您的 3 个查询转换为 1 个

您的示例似乎表明您的所有 3 个表都具有相同的列数。如果列也是相同的类型,那么您可以合并查询,并将它们加载到单个表适配器中并将它们填充到单个强类型数据表中。然后,您可能需要做更多的工作来将它们拆分为单独的数据表。也许修改查询以返回一列,以便您可以跟踪数据的来源:

Select 'tableA' as wherefrom, ColA, ColB, ColC from TableA
UNION ALL
Select 'tableB' as wherefrom, ColD, ColE, ColF from TableB
UNION ALL
Select 'tableC' as wherefrom, ColG, ColH, ColI from TableC

这是一团糟,一个麻烦,一个黑客


为什么这么难?好吧.. 引用另一句老话:如果很难,那你就做错了。 TableAdapters 是以 X 方式设计的,而您正试图以 Y 方式使用它们。退后一步,检查你这样做的原因——这才是真正的问题所在

【讨论】:

  • 在这种情况下,强类型数据集应该称为强类型数据表
  • 之所以称为数据集,是因为它是数据表的集合。数据表与数据库或数据库表无关,它们是客户端数据的表(行和列)。它们与数据库表有一些相似之处,但只是在字符串与书籍有一些相似之处的意义上。表格适配器通常使用数据库数据填充数据表,但它们可以从任何地方填充。仅仅因为单个 tableadapter 不会从多个数据库查询中填充多个数据表并不意味着数据集应该被称为数据表
  • 这是关于 stackoverflow 的可悲之处之一 - 你花了很长时间和大量的努力来尝试教育,写出比大多数答案更全面的答案,而你没有甚至得到一个支持/感谢
猜你喜欢
  • 1970-01-01
  • 2012-08-03
  • 2020-03-27
  • 2011-04-30
  • 1970-01-01
  • 1970-01-01
  • 2017-02-22
  • 2014-10-11
  • 1970-01-01
相关资源
最近更新 更多