- 題名: DatasetからRecordsetへの変換
- 日時: 2014/03/19 17:26:47
- ID: 32198
- この記事の返信元:
- (なし)
- この記事への返信:
- [32200] Re[1]: DatasetからRecordsetへの変換2014/03/19 18:48:49
- [32201] Re[1]: DatasetからRecordsetへの変換2014/03/19 18:56:21
- ツリーを表示
■No32198に返信(さくらさんの記事) > Dataset(System.Data.Dataset)に入っているデータを > ADODB.Recordsetに移すことは可能でしょうか? DataTable → Recordset ではなく、 DataSet → Recordset なのですか? 複数のテーブルのリレーション構造を、Recordset で表現するのは難しいです。 ある程度までは、MSDataShape プロバイダーで表現できますが…。 とりあえず下記では、DataTable に対して ToRecordset メソッドを追加してみました。 Module Module1 #Region "DataTable から Recordset への変換" <System.Runtime.CompilerServices.Extension()> _ Public Function ToRecordset(tbl As DataTable) As ADODB.Recordset Dim rs As New ADODB.Recordset Dim fields As New ArrayList() For Each col As DataColumn In tbl.Columns Dim n = col.ColumnName fields.Add(n) Dim t = Convert(col.DataType) Dim a = ADODB.FieldAttributeEnum.adFldUpdatable If col.ReadOnly Then a = a And Not ADODB.FieldAttributeEnum.adFldUpdatable If col.AllowDBNull Then a = a Or ADODB.FieldAttributeEnum.adFldIsNullable If a = 0 Then a = ADODB.FieldAttributeEnum.adFldUnspecified rs.Fields.Append(n, t, 0, a) Next Dim cols = fields.ToArray() rs.Open() For Each row As DataRow In tbl.Rows If row.RowState = DataRowState.Deleted Then Continue For rs.AddNew(cols, row.ItemArray) Next If Not rs.EOF Then rs.MoveFirst() Return rs End Function Private Function Convert(t As Type) As ADODB.DataTypeEnum Select Case t Case GetType(DateTime) : Return ADODB.DataTypeEnum.adDBTime Case GetType(Decimal) : Return ADODB.DataTypeEnum.adDecimal Case GetType(Boolean) : Return ADODB.DataTypeEnum.adBoolean Case GetType(Integer) : Return ADODB.DataTypeEnum.adInteger Case GetType(Single) : Return ADODB.DataTypeEnum.adSingle Case GetType(Double) : Return ADODB.DataTypeEnum.adDouble Case GetType(Byte()) : Return ADODB.DataTypeEnum.adBinary Case GetType(String) : Return ADODB.DataTypeEnum.adBSTR Case GetType(Short) : Return ADODB.DataTypeEnum.adSmallInt Case GetType(Byte) : Return ADODB.DataTypeEnum.adTinyInt Case GetType(Long) : Return ADODB.DataTypeEnum.adBigInt Case Else : Return ADODB.DataTypeEnum.adVarWChar End Select End Function #End Region End Module
■No32201に追記(魔界の仮面弁士の記事) > DataTable.WriteXml で保存して、それを > Workbooks.OpenXML "C:\TEMP\TEST.XML" , , xlXmlLoadImportToList > で読み込ませてみるとか。 さらに別案。VBA 側で Set rs = CreateObject("ADODB.Recordset") rs.Open "C:\TEMP\SAMPLE.XML" で読み取れるタイプの XML ファイルを .NET 側で生成してみました。 これは、 「rs.Save "C:\TEMP\SAMPLE.XML", adPersistXML」 で出力されるタイプのファイル形式です。 (本来は編集状態なども管理できる形式ですが、ここでは細かい情報を端折っています) 参考資料: http://support.microsoft.com/KB/316337 '-------------------------------------------------- Imports <xmlns:rs='urn:schemas-microsoft-com:rowset'> Imports <xmlns:z='#RowsetSchema'> Imports <xmlns:s='uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882'> Imports <xmlns:dt='uuid:C2F41010-65B3-11d1-A29F-00AA00C14882'> Module Module1 Public Sub PersistXML(ByVal tbl As DataTable, filePath As String) Dim doc = <xml xmlns:s='uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882' xmlns:dt='uuid:C2F41010-65B3-11d1-A29F-00AA00C14882' xmlns:rs='urn:schemas-microsoft-com:rowset' xmlns:z='#RowsetSchema'> <s:Schema id='RowsetSchema'> <s:ElementType name="row" content="eltOnly" rs:updatable="true"> <%= tbl.Columns.OfType(Of DataColumn)(). Select(Function(c, i) GetSchema(c, i + 1)) %> </s:ElementType> </s:Schema> <rs:data> <rs:insert> <%= From row In tbl.AsEnumerable() Where (row.RowState <> DataRowState.Deleted) Select <z:row <%= From col As DataColumn In tbl.Columns Select New XAttribute(col.ColumnName, row(col)) %>/> %> </rs:insert> </rs:data> </xml> doc.Save(filePath) End Sub Private Function GetSchema(col As DataColumn, idx As Integer) As XElement Dim tname As String ' dt:type 属性値を決定しているところ。面倒ならすべて string でも可。 Select Case col.DataType Case GetType(Date) : tname = "dateTime" Case GetType(String) : tname = "string" Case GetType(Integer) : tname = "int" 'Case GetType(Decimal) : tname = "number" '※ Case Else : tname = "float" End Select '※ dt:type="number" 型も使えるが、その場合は rs:dbtype 属性が必要 Dim elm = <s:AttributeType name=<%= col.ColumnName %> rs:number=<%= idx %> rs:write="true"> <s:datatype dt:type=<%= tname %> dt:maxLength=<%= col.MaxLength %> rs:maybenull=<%= col.AllowDBNull %> /> </s:AttributeType> Return elm End Function End Module
■No32202に返信(さくらさんの記事) > 試すのが楽しみです。 > 進んで出勤したい気分なんて久々です(笑) 失礼しました。 うっかり、VB2008 という箇所を読み落としていました。 そのままだとコンパイルエラーとなりますので、適宜修正をお願いします。 No32200 & No32204 > Case GetType(DateTime) .NET 4 の System.Type には 比較演算子が実装されていますが、 .NET 3.5 以下の System.Type には、比較演算子が実装されていません。 そのため VB2008 では、 先述の「Select Case Type値」構文は コンパイルエラーとなってしまいます。 型の .FullName による比較で代用するか、もしくは If 文を用いた表現などに置き換えてみてください。 No32204 > Dim doc = > <xml この部分では、行継続文字(行末の「空白+アンダーバー」)を省略しています。 VB2008 の場合は、上記箇所でエラーとなるため、 Dim doc = _ <xml のように記述するか、もしくは Dim doc = <xml のように、改行せずに記述するようにしてください。 また、<s:ElementType> 直下に置いた > <%= tbl.Columns.OfType(Of DataColumn)(). > Select(Function(c, i) GetSchema(c, i + 1)) %> と書かれている Linq 式の記述に対しても、 <%= tbl.Columns.OfType(Of DataColumn)(). _ Select(Function(c, i) GetSchema(c, i + 1)) %> のように、行末に「 _」の行継続文字を補完する必要があります。 <rs:insert> 直下の Linq 構文も同様です。
分類:[.NET]
VB2008にて開発しています。
Dataset(System.Data.Dataset)に入っているデータを
ADODB.Recordsetに移すことは可能でしょうか?
逆のRecordsetの内容をDatasetに入れる方法なら見つかるのですが
その反対が見つかりません。
目的としては、DBからDatasetへデータを取得するvb.netのDLLがあり
それを根幹の部分は変えずにExcelVBAで使えるようにしたいのです。
Excel側ではRecordsetのように1行ずつ読み込んで処理したり
フィールド名を指定して値を読み込んだりといった
ことがしたいです。
ですので、Recordsetに変換できるのなら一番ありがたいですが、
無理であれば他のExcelVBAで扱えるデータ形式に変換するのでもかまいません。
ちなみに、今まで試した方法としては、
dataset.writexmlでXMLの文字列にしてExcelに渡し、
それをExcel側でMSXML2.DOMDocumentオブジェクトに入れるところまでは
成功したのですが、どうも使い勝手が悪いようで、他の方法を探しています。
アドバイスいただけますと助かります。