C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[5]: テーブルのデータをXMLファイルに出力したい


(過去ログ 152 を表示中)

[トピック内 12 記事 (1 - 12 表示)]  << 0 >>

■88328 / inTopicNo.1)  テーブルのデータをXMLファイルに出力したい
  
□投稿者/ 河童 (19回)-(2018/08/21(Tue) 17:56:12)

分類:[.NET 全般] 

いつもお世話になっております。
データベースのテーブルのデータを丸ごとXMLファイルに出力したいと思っています。
環境
VS2010
MySQL5.5

取得したデータをリスト型の「user」に代入して
「user」をXMLファイルに出力しようとしていますが、
エラーが発生します。

分からないことは、
テーブルのデータをどのようにXMLファイルに
出力するかです。

よろしくお願いします。



        private void btnExp_Click(object sender, EventArgs e)
        {
            m_User u = new m_User();

            seach_motikensaku s = new seach_motikensaku();
            // DBのデータを抽出する
            List<m_User> user = Get_m_user();

            // シリアライズ先のファイル
            const string xmlFile = @".\Sample.xml";
            // シリアライズするオブジェクト
            //var obj = new Sample { Id = 7, Text = "@IT" }; 

            // シリアライズする
            //var xmlSerializer1 = new XmlSerializer(typeof(Sample));
            var xmlSerializer1 = new XmlSerializer(typeof(m_User));

            using (var streamWriter = new StreamWriter(xmlFile, false, Encoding.UTF8))
            {
                //xmlSerializer1.Serialize(streamWriter, obj);

                // XML ドキュメントを生成中にエラーが発生
                xmlSerializer1.Serialize(streamWriter, user);
                streamWriter.Flush();
            }

        }

引用返信 編集キー/
■88329 / inTopicNo.2)  Re[1]: テーブルのデータをXMLファイルに出力したい
□投稿者/ 魔界の仮面弁士 (1786回)-(2018/08/21(Tue) 18:13:27)
2018/08/21(Tue) 18:14:11 編集(投稿者)

No88328 (河童 さん) に返信
> 取得したデータをリスト型の「user」に代入して
> List<m_User> user = Get_m_user();

m_User 型の構造が分かると、より具体的な話ができるかもしれません。

https://social.msdn.microsoft.com/Forums/netframework/ja-JP/50517648-0b31-469e-9671-a8e7671f18df/1247112522124501252321270123641239112365124141237912435


> 「user」をXMLファイルに出力しようとしていますが、
> エラーが発生します。
> // XML ドキュメントを生成中にエラーが発生
> xmlSerializer1.Serialize(streamWriter, user);

そのエラーの内容はどのようなものでしょうか?

たとえば、m_User が「引数 0 個の public なコンストラクタ」をもっていない場合、
シリアライズ時に InvalidOperationException が発生したりしますね。


なお、XmlSerializer 以外の手法もあります。
http://bbs.wankuma.com/index.cgi?mode=al2&namber=77571&KLOG=131
引用返信 編集キー/
■88330 / inTopicNo.3)  Re[2]: テーブルのデータをXMLファイルに出力したい
□投稿者/ 河童 (20回)-(2018/08/21(Tue) 18:41:56)
こんばんは。魔界の仮面弁士さん、お返事ありがとうございます。

>>取得したデータをリスト型の「user」に代入して
>>List<m_User> user = Get_m_user();

> m_User 型の構造が分かると、より具体的な話ができるかもしれません。

m_Userというクラスです。
省略していますが、テーブルの各フィールに対応する変数を作っています。

public class m_User
{
public string user_id { get; set; }
public string user_name { get; set; }

}

>>// XML ドキュメントを生成中にエラーが発生
>>xmlSerializer1.Serialize(streamWriter, user);
> そのエラーの内容はどのようなものでしょうか?
「InvalidOperationExcepionはハンドルされませんでした。」
というエラーが発生しています。

変数userには、データは入っています。


> たとえば、m_User が「引数 0 個の public なコンストラクタ」をもっていない場合、
> シリアライズ時に InvalidOperationException が発生したりしますね。
ここはどういう意味でしょうか?
確かにInvalidOperationExceptionというエラーが発生しています。

今回考えている処理としては、
データをXMLファイルに一度出力して、
別のDBと比較対象用に利用するつもりです。
XMLファイルの書き出しと読込ができるようになりたいです。


引用返信 編集キー/
■88331 / inTopicNo.4)  Re[1]: テーブルのデータをXMLファイルに出力したい
□投稿者/ WebSurfer (1580回)-(2018/08/21(Tue) 18:43:50)
No88328 (河童 さん) に返信

> 取得したデータをリスト型の「user」に代入して
>「user」をXMLファイルに出力しようとしていますが

List<User> ではなくて DataSet に取得して、DataSet.WriteXml(filepath, XmlWriteMode.WriteSchema);
のようにして XML ファイルを作成するという方法はいかがですか?

引用返信 編集キー/
■88332 / inTopicNo.5)  Re[3]: テーブルのデータをXMLファイルに出力したい
□投稿者/ 河童 (21回)-(2018/08/21(Tue) 18:44:56)
申し訳ありません。
コードはC#で書いています。
引用返信 編集キー/
■88333 / inTopicNo.6)  Re[4]: テーブルのデータをXMLファイルに出力したい
□投稿者/ WebSurfer (1581回)-(2018/08/21(Tue) 19:15:28)
No88332 (河童 さん) に返信
> 申し訳ありません。
> コードはC#で書いています。

誰に対するレスですか?

私に対するものなら C# で書きましたけど。そもそも、上の私のレスに書いた範囲であれば
C# でも VB.NET でも同じことですが・・・
引用返信 編集キー/
■88334 / inTopicNo.7)  Re[2]: テーブルのデータをXMLファイルに出力したい
□投稿者/ 河童 (22回)-(2018/08/21(Tue) 19:53:24)
WebSurferさん、ありがとうございます。

リストのデータをforeachで繰り返して
DataSetに取得させてから
XMLファイルに出力することができました。


DataSet ds = new DataSet();
DataTable dt = ds.Tables.Add("m_user");
DataRow dr;

string xmlFile;
xmlFile = @".\m_user.xml";

dt.Columns.Add("user_id");
dt.Columns.Add("user_name");

foreach (m_User item in user)
{
dr = dt.NewRow();
dr["user_id"] = item.user_id;
dr["user_name"] = item.user_name;
dt.Rows.Add(dr);
}
ds.WriteXml(xmlFile);
解決済み
引用返信 編集キー/
■88335 / inTopicNo.8)  Re[3]: テーブルのデータをXMLファイルに出力したい
□投稿者/ WebSurfer (1582回)-(2018/08/21(Tue) 21:06:53)
No88334 (河童 さん) に返信

> リストのデータをforeachで繰り返して
> DataSetに取得させてから

MySQL ですよね? Connector/NET は使っているのですよね?

であれば、「リストのデータ」を作る必要はなくて、ADO.NET + Connector/NET
を使って MySQL から直接 DataSet を作ることができるはずです。

それも検討されてはいかがですか。
解決済み
引用返信 編集キー/
■88339 / inTopicNo.9)  Re[3]: テーブルのデータをXMLファイルに出力したい
□投稿者/ 魔界の仮面弁士 (1787回)-(2018/08/22(Wed) 11:03:53)
2018/08/22(Wed) 11:36:49 編集(投稿者)

No88330 (河童 さん) に返信
> 確かにInvalidOperationExceptionというエラーが発生しています。

原因はここ。

var xmlSerializer1 = new XmlSerializer(typeof(m_User));
xmlSerializer1.Serialize(streamWriter, user);

「m_User」用のシリアライザを用いて、
「m_User」ではなく「List<m_User>」をシリアライズしていますよね。

ゆえに型変換エラー(InvalidCastException)の内部例外により、
処理失敗(InvalidOperationException)が通知されるわけです。

シリアライザの型を見直せば、一応解決します。
var xmlSerializer1 = new XmlSerializer(typeof(List<m_User>));



>>たとえば、m_User が「引数 0 個の public なコンストラクタ」をもっていない場合、
>>シリアライズ時に InvalidOperationException が発生したりしますね。
> ここはどういう意味でしょうか?

※私の発言に対する質問だったので、
 あえて解決済みマークは外して回答しています。


コンストラクタとは、ザックリ言えば、new で呼び出される処理のことです。
 m_User u = new m_User(); // 引数無しコンストラクタの呼び出し
 m_User u = new m_User("88330", "河童"); // 引数2つ(string, string)なコンストラクタの呼び出し

引数無しコンストラクタがない、または、あってもそれが private であるような場合、
デシリアライズ時にインスタンスを生成できず、InvalidOperationException の例外となります。

とはいえ今回の場合、new m_User() が使えるようになっているようなので、
コンストラクタの問題ではありません。


m_User u = new m_User() { user_id = "88330", user_name = "河童" };

var xmlSerializer1 = new XmlSerializer(typeof(m_User));
using (var streamWriter = new StreamWriter(xmlFile, false, Encoding.UTF8))
{
  // xmlSerializer1.Serialize(streamWriter, user); // これは NG
  xmlSerializer1.Serialize(streamWriter, u); // これは OK
  streamWriter.Flush();
}


上記は「m_User 用のシリアライザ」に「m_User 型のインスタンス」を
シリアライズ(永続化)させた例であり、下記の XML が生成されます。

<?xml version="1.0" encoding="utf-8"?>
<user xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <user_id>88330</user_id>
 <user_name>河童</user_name>
</user>


ちなみに、もしも XML宣言および名前空間が邪魔で、もっとシンプルに

<m_User>
 <user_id>88330</user_id>
 <user_name>河童</user_name>
</m_User>

と出力させたいのであれば、シリアライズ処理を下記のように書き換えることで対応できます。

using (var streamWriter = new StreamWriter(xmlFile, false, Encoding.UTF8))
using (var xmlWriter = XmlWriter.Create(streamWriter, new XmlWriterSettings() { OmitXmlDeclaration = true }))
{
 var ns = new XmlSerializerNamespaces();
 ns.Add("", "");
 xmlSerializer1.Serialize(xmlWriter, u, ns);
 streamWriter.Flush();
}


また、m_User クラスに属性指定を行うことで、XML の形式を変化させることもできます。

 [XmlRoot("user")]
 public class m_User
 {
  [XmlAttribute("id")] public string user_id { get; set; }
  [XmlText()] public string user_name { get; set; }
 }

上記の場合、シリアライズ結果がこのように変化し、さらにシンプルな XML となります。

<user id="88330">河童</user>



> データをXMLファイルに一度出力して、
> 別のDBと比較対象用に利用するつもりです。

データベースの比較を行うことが目的なのでしょうか。
XmlSerializer の使い方を学ぶことが目的なのでしょうか。
事前に定めておいた書式の XML ファイルを生成する(あるいは読み取る)ことが目的なのでしょうか。


> XMLファイルの書き出しと読込ができるようになりたいです。

XmlSerializer で永続化(シリアライズ)する場合、「XML として無効なデータ」が
存在するかどうかを気にしておいたほうが良いでしょう。

仮に m_User の内容が
 u = new m_User() { user_id = "88330", user_name = "河\u001a童" };
だったりすると、Serialize は成功しますが、Deserialize は失敗します。


また、現状の方法だと、
 public int user_id { get; set; }
なデータと
 public string user_id { get; set; }
なデータを区別してシリアライズすることが難しいという問題もあります。
引用返信 編集キー/
■88340 / inTopicNo.10)  Re[3]: テーブルのデータをXMLファイルに出力したい
□投稿者/ 魔界の仮面弁士 (1788回)-(2018/08/22(Wed) 11:25:06)
No88334 (河童 さん) に返信
> ds.WriteXml(xmlFile);

上記は
 ds.WriteXml(xmlFile, XmlWriteMode.IgnoreSchema);
と同義になります。


データの比較だけではなく、データ型まで含めて比較する必要があるのなら、
 ds.WriteXml(xmlFile, XmlWriteMode.WriteSchema);
のようにした方が良いかも知れません。

これは上記 No88339 で述べた
 public int user_id { get; set; }
 public string user_id { get; set; }
なデータを区別する必要がある場合に役に立ちます。
今回は DataTable なので、
 dt.Columns.Add("user_id", typeof(int));
 dt.Columns.Add("user_id", typeof(string));
の違いを考慮する必要があるかどうか、という意味です。



あるいは、スキーマの同一性は保証されていて、
複数のデータベース間でのデータ同期(バッチ更新処理)が目的なら、
 ds.WriteXml(xmlFile, XmlWriteMode.DiffGram);
の方が良いこともあります。
参考までに、DiffGram を指定した場合との違いを示しておきます。


DataSet ds = new DataSet();
DataTable dt = ds.Tables.Add("m_user");
dt.Columns.Add("user_id");
dt.Columns.Add("user_name");
dt.PrimaryKey = new DataColumn[] { dt.Columns["user_id"] };
dt.Rows.Add("100", "ジャレコ");
dt.Rows.Add("200", "山梨シルクセンター");
//
// この時点では、2 行とも「新規追加行」なので
//  dt.Rows[0].RowState は Added
//  dt.Rows[1].RowState は Added
// という状態です。
//

ds.AcceptChanges(); // 変更を確定
//
// この時点では、変更が確定されているため、
//  dt.Rows[0].RowState は Unchanged
//  dt.Rows[1].RowState は Unchanged
// すなわち「未変更」状態です。
// データベースから SELECT した直後のデータは、通常この状態となります。
//
// 何らかの理由で DataSet を手動で構築しなければならない場合には、
// このように AcceptChanges を呼んでおき、未編集状態である
// Unchanged にしておいた方が良いでしょう。


// 100 番のレコード "ジャレコ" を削除状態にする
dt.Rows.Find("100").Delete();

// 200 番の名前を、"山梨シルクセンター" から "サンリオ" に変更
dt.Rows.Find("200")["user_name"] = "サンリオ";

// 上記の編集により、各行の RowState は
//  dt.Rows[0].RowState は Deleted
//  dt.Rows[1].RowState は Modified
// に変化しています。


// 例1:編集履歴は失われ、DataSet 上の最後の状態のみが出力されます
ds.WriteXml(xmlFile1);

// 例2:復元時に RowState の状態まで維持されます。
ds.WriteXml(xmlFile2, XmlWriteMode.DiffGram);



【例1の出力結果】… dt.Rows.Count は 2 件だったが、出力結果は 1 件のみとなる
<?xml version="1.0" standalone="yes"?>
<NewDataSet>
 <m_user>
  <user_id>200</user_id>
  <user_name>サンリオ</user_name>
 </m_user>
</NewDataSet>


【例2の出力結果】… 編集前の値も保持されている
<?xml version="1.0" standalone="yes"?>
<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
 <NewDataSet>
  <m_user diffgr:id="m_user2" msdata:rowOrder="1" diffgr:hasChanges="modified">
   <user_id>200</user_id>
   <user_name>サンリオ</user_name>
  </m_user>
 </NewDataSet>
 <diffgr:before>
  <m_user diffgr:id="m_user1" msdata:rowOrder="0">
   <user_id>100</user_id>
   <user_name>ジャレコ</user_name>
  </m_user>
  <m_user diffgr:id="m_user2" msdata:rowOrder="1">
   <user_id>200</user_id>
   <user_name>山梨シルクセンター</user_name>
  </m_user>
 </diffgr:before>
</diffgr:diffgram>
引用返信 編集キー/
■88343 / inTopicNo.11)  Re[4]: テーブルのデータをXMLファイルに出力したい
□投稿者/ 河童 (23回)-(2018/08/22(Wed) 12:39:08)
こんにちは。魔界の仮面弁士さん、お返事ありがとうございます。

アドバイスのほとんど理解できていない状態ですが、
いつもプログラミングは奥が深いなぁと思ってしまいます。

自分は何か困ったことがあれば、
仕事半分、趣味半分でプログラムをさわっています。

今回は、パソコンが壊れる前のDBと
代替機で使用していた期間のDBを比較して
データを一つにまとめようとしています。

一方のDBをXMLで出力して、
XMLファイルを読込でもう一方のDBに
新規追加または更新の処理をかける。

例外的な処理なので、一度しか使わないのですが、
勉強のため
1.XMLファイルの出力、
2.XMLファイルの読込、
3.読込したデータを使用してSQL文の生成して発行
に挑戦しています。


引用返信 編集キー/
■88347 / inTopicNo.12)  Re[5]: テーブルのデータをXMLファイルに出力したい
□投稿者/ 魔界の仮面弁士 (1789回)-(2018/08/22(Wed) 13:13:27)
No88343 (河童 さん) に返信
> 1.XMLファイルの出力、
> 2.XMLファイルの読込、
> 3.読込したデータを使用してSQL文の生成して発行

だったら、MySqlDataAdapter クラスを使いましょう。

これの Fill メソッドを使うことで、SELECT な SQL 文で取得した結果を
DataSet に保持できます。(各行は Unchanged な状態)

DataSet の WriteXml メソッドで XML 化する方法は既出なので省略。
XML から DataSet への復元は、DataSet の ReadXml メソッドで OK です。


データの追加・削除・編集は、DataSet に対して行うようにします。
DataGridView 等に表示して編集しても OK。


そうして編集した DataSet の内容をデータベースに反映させるには、
MySqlDataAdapter の Update メソッドに渡すだけです。
ただしその前に、MySqlCommandBuilder を噛ませるのを忘れずに。

https://ameblo.jp/tetsuya-staff/entry-10157130800.html
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -