これは長い質問になるでしょう - 私はこの問題を解決するために一日中費やしてきたので、おそらく皆さんが助けてくれるでしょう! 新しい構造 (XML 形式) が提示されたときにデータベース構造を変更できるようにすることで、データベース アプリケーションの将来性を保証しようとしています。
現在、データベース構造を XML にうまくエクスポートできています。以下の作業コードを参照してください。
public void generateXMLStructureCompactDB(string fileName)
{
DataTable table = new DataTable();
int position;
FileStream fsWrite;
StreamWriter sw;
string version = "1.1.1.0";
table.Columns.Add("TableName", Type.GetType("System.String"));
table.Columns.Add("ColName", Type.GetType("System.String"));
table.Columns.Add("Position", Type.GetType("System.Int32"));
table.Columns.Add("DataType", Type.GetType("System.String"));
table.Columns.Add("MaximumLength", Type.GetType("System.Int32"));
table.Columns.Add("Precision", Type.GetType("System.Int32"));
table.Columns.Add("Scale", Type.GetType("System.Int32"));
table.Columns.Add("Nullable", Type.GetType("System.Boolean"));
table.Columns.Add("Identity", Type.GetType("System.Boolean"));
table.Columns.Add("IdentitySeed", Type.GetType("System.Int32"));
table.Columns.Add("IdentityIncrement", Type.GetType("System.Int32"));
string sql = "select Table_Name, Column_Name, Ordinal_Position, Data_Type, " +
"Character_Maximum_Length, Numeric_Precision, Numeric_Scale, Is_Nullable, " +
"case when AutoInc_Seed is null then 0 else 1 end as IS_IDENTITY, " +
"AutoInc_Seed, AutoInc_Increment from information_schema.columns";
runSQL(sql, out table);
if (File.Exists(fileName))
File.Delete(fileName);
fsWrite = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
sw = new StreamWriter(fsWrite, Encoding.ASCII);
XmlWriter writer = new XmlTextWriter(sw);
writer.WriteStartDocument(false);
writer.WriteRaw(Environment.NewLine);
writer.WriteComment("DBVersion=" + DBVersion + ", created=" + DateTime.Now.ToString());
writer.WriteRaw(Environment.NewLine);
writer.Close();
sw.Close();
fsWrite.Close();
fsWrite = new FileStream(fileName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
sw = new StreamWriter(fsWrite, Encoding.ASCII);
DataTable indexes = new DataTable();
indexes.Columns.Add("TableName", Type.GetType("System.String"));
indexes.Columns.Add("Schema", Type.GetType("System.String"));
indexes.Columns.Add("IndexName", Type.GetType("System.String"));
indexes.Columns.Add("Clustered", Type.GetType("System.Boolean"));
indexes.Columns.Add("Unique", Type.GetType("System.Boolean"));
indexes.Columns.Add("IndexColName", Type.GetType("System.String"));
sql = "select Table_Name, Table_Schema, Index_Name, [Clustered], [Unique], " +
"Column_Name from information_schema.indexes";
runSQL(sql, out indexes);
table.TableName = "Tables";
indexes.TableName = "Indexes";
table.WriteXml(sw);
sw.WriteLine("");
indexes.WriteXml(sw);
sw.Close();
fsWrite.Close();
}
以下は、生成された XML ファイルです (実際のバージョンはもっと大きいですが、1 つのテーブルと 1 つのインデックスに切り詰めました)。
<?xml version="1.0" encoding="us-ascii" standalone="no"?>
<!--DBVersion=1.0.0.0, created=14/03/2013 13:18:20-->
<DocumentElement>
<Tables>
<TABLE_NAME>ContactLog</TABLE_NAME>
<COLUMN_NAME>ContactLogId</COLUMN_NAME>
<ORDINAL_POSITION>1</ORDINAL_POSITION>
<DATA_TYPE>int</DATA_TYPE>
<NUMERIC_PRECISION>10</NUMERIC_PRECISION>
<IS_NULLABLE>NO</IS_NULLABLE>
<IS_IDENTITY>1</IS_IDENTITY>
<AUTOINC_SEED>1</AUTOINC_SEED>
<AUTOINC_INCREMENT>1</AUTOINC_INCREMENT>
</Tables>
<Tables>
<TABLE_NAME>ContactLog</TABLE_NAME>
<COLUMN_NAME>CustomerId</COLUMN_NAME>
<ORDINAL_POSITION>2</ORDINAL_POSITION>
<DATA_TYPE>int</DATA_TYPE>
<NUMERIC_PRECISION>10</NUMERIC_PRECISION>
<IS_NULLABLE>YES</IS_NULLABLE>
<IS_IDENTITY>0</IS_IDENTITY>
</Tables>
<Tables>
<TABLE_NAME>ContactLog</TABLE_NAME>
<COLUMN_NAME>ContactDate</COLUMN_NAME>
<ORDINAL_POSITION>3</ORDINAL_POSITION>
<DATA_TYPE>datetime</DATA_TYPE>
<NUMERIC_PRECISION>23</NUMERIC_PRECISION>
<NUMERIC_SCALE>3</NUMERIC_SCALE>
<IS_NULLABLE>YES</IS_NULLABLE>
<IS_IDENTITY>0</IS_IDENTITY>
</Tables>
<Tables>
<TABLE_NAME>ContactLog</TABLE_NAME>
<COLUMN_NAME>ContactTypeId</COLUMN_NAME>
<ORDINAL_POSITION>4</ORDINAL_POSITION>
<DATA_TYPE>int</DATA_TYPE>
<NUMERIC_PRECISION>10</NUMERIC_PRECISION>
<IS_NULLABLE>YES</IS_NULLABLE>
<IS_IDENTITY>0</IS_IDENTITY>
</Tables>
<Tables>
<TABLE_NAME>ContactLog</TABLE_NAME>
<COLUMN_NAME>AuditText</COLUMN_NAME>
<ORDINAL_POSITION>5</ORDINAL_POSITION>
<DATA_TYPE>nvarchar</DATA_TYPE>
<CHARACTER_MAXIMUM_LENGTH>2048</CHARACTER_MAXIMUM_LENGTH>
<IS_NULLABLE>YES</IS_NULLABLE>
<IS_IDENTITY>0</IS_IDENTITY>
</Tables>
<Tables>
<TABLE_NAME>ContactType</TABLE_NAME>
<COLUMN_NAME>ContactTypeId</COLUMN_NAME>
<ORDINAL_POSITION>1</ORDINAL_POSITION>
<DATA_TYPE>int</DATA_TYPE>
<NUMERIC_PRECISION>10</NUMERIC_PRECISION>
<IS_NULLABLE>NO</IS_NULLABLE>
<IS_IDENTITY>1</IS_IDENTITY>
<AUTOINC_SEED>1</AUTOINC_SEED>
<AUTOINC_INCREMENT>1</AUTOINC_INCREMENT>
</Tables>
</DocumentElement>
<DocumentElement>
<Indexes>
<TABLE_NAME>ContactLog</TABLE_NAME>
<INDEX_NAME>PK_ContactLog</INDEX_NAME>
<CLUSTERED>false</CLUSTERED>
<UNIQUE>true</UNIQUE>
<COLUMN_NAME>ContactLogId</COLUMN_NAME>
</Indexes>
</DocumentElement>
これは、XML ファイルを読み取るコードの一部です。tables
XML ファイルには、 (実際には列のリストである) 2 つの別個のテーブルの列とindexes
、インデックスのリストが含まれています。の位置に基づいてファイルを 2 つに分割し<DocumentElement>
、2 つの XML 要素を 2 つの別個のテーブルに配置します。以下のコードを参照してください。
static bool VerifyStructure()
{
FileStream fsWrite;
int i;
StreamWriter sw;
string DBStructureVersion = "0.0.0.0";
string xmlFile;
string s;
string tmp = Environment.GetEnvironmentVariable("TEMP");
if (tmp == "")
tmp = Environment.GetEnvironmentVariable("SystemDrive");
try
{
xmlFile = tmp + @"\dbStructure.xml";
if (File.Exists(xmlFile))
File.Delete(xmlFile);
fsWrite = new FileStream(xmlFile, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
sw = new StreamWriter(fsWrite, Encoding.ASCII);
sw.Write(syntos.Properties.Resources.dbStructure);
sw.Close();
fsWrite.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error reading structure xml file: " + ex.Message);
return false;
}
if (!File.Exists(xmlFile))
{
MessageBox.Show("XML Structure file '" + xmlFile + "' does not exist.");
return false;
}
StreamReader sr = new StreamReader(xmlFile);
s = sr.ReadLine();
while (s != null)
{
if (s.Contains("DBVersion="))
{
i = s.IndexOf("DBVersion=");
DBStructureVersion = s.Substring(i + 10);
i = DBStructureVersion.IndexOf(",");
DBStructureVersion = DBStructureVersion.Substring(0, i);
break;
}
s = sr.ReadLine();
}
sr.Close();
// Split the remaining XML file into two: table datatable file and index datatable file
// Write out to file1 all the table information and to file2 all the index information
string file1path;
string file2path;
try
{
file1path = tmp + @"\tables.xml";
file2path = tmp + @"\indexes.xml";
if (File.Exists(file1path))
File.Delete(file1path);
if (File.Exists(file2path))
File.Delete(file2path);
FileStream fsw1 = new FileStream(file1path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
FileStream fsw2 = new FileStream(file2path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
StreamWriter sw1 = new StreamWriter(fsw1, Encoding.ASCII);
StreamWriter sw2 = new StreamWriter(fsw2, Encoding.ASCII);
// Create a file containing just the table / column definitions
sr = new StreamReader(xmlFile);
s = sr.ReadToEnd();
sr.Close();
i = s.IndexOf("<DocumentElement>");
s = s.Substring(i);
i = s.IndexOf("</DocumentElement>");
s = s.Substring(0, i + 18);
sw1.Write(s);
sw1.Close();
fsw1.Close();
// Create a file containing the index column definitions
sr = new StreamReader(xmlFile);
s = sr.ReadToEnd();
sr.Close();
i = s.IndexOf("</DocumentElement>");
s = s.Substring(i + 18);
sw2.Write(s);
sw2.Close();
fsw2.Close();
sr.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error producing the table and index XML file. " + ex.Message);
return false;
}
DataTable table = new DataTable();
table.Columns.Add("TableName", Type.GetType("System.String"));
table.Columns.Add("ColName", Type.GetType("System.String"));
table.Columns.Add("Position", Type.GetType("System.Int32"));
table.Columns.Add("DataType", Type.GetType("System.String"));
table.Columns.Add("MaximumLength", Type.GetType("System.Int32"));
table.Columns.Add("Precision", Type.GetType("System.Int32"));
table.Columns.Add("Scale", Type.GetType("System.Int32"));
table.Columns.Add("Nullable", Type.GetType("System.Boolean"));
table.Columns.Add("Identity", Type.GetType("System.Boolean"));
table.Columns.Add("IdentitySeed", Type.GetType("System.Int32"));
table.Columns.Add("IdentityIncrement", Type.GetType("System.Int32"));
table.TableName = "Tables";
DataTable indexes = new DataTable();
indexes.Columns.Add("TableName", Type.GetType("System.String"));
indexes.Columns.Add("Schema", Type.GetType("System.String"));
indexes.Columns.Add("IndexName", Type.GetType("System.String"));
indexes.Columns.Add("Clustered", Type.GetType("System.Boolean"));
indexes.Columns.Add("Unique", Type.GetType("System.Boolean"));
indexes.Columns.Add("IndexColName", Type.GetType("System.String"));
indexes.TableName = "Indexes";
// Read in the XML for the table / columns
sr = new StreamReader(file1path);
table.ReadXml(sr);
sr.Close();
if (table.Rows.Count == 0)
{
MessageBox.Show("No loadable table rows found in XML file");
sw.Close();
fsWrite.Close();
return false;
}
sr = new StreamReader(file2path);
indexes.ReadXml(sr);
sr.Close();
if (indexes.Rows.Count == 0)
{
MessageBox.Show("No loadable index rows found in XML file");
sw.Close();
fsWrite.Close();
return false;
}
DbFunctions.BackupDatabase();
bool success1 = CreateTempTables(table);
return true;
}
ブレークポイントとデバッグ ステートメントを使用すると、テーブルに正しい数の行と列が入力されていることがわかりますが、これらはすべて null です。空のセルだけです。私はtable.Rows.Count
、このテーブルに実際に行があることをよく知っていました。
私がここで正しい方向に進んでいるかどうかを誰かに見てもらえたら、私は永遠に感謝します! 前もって感謝します :)
編集: 別の XML シートでこれをテストしましたが、動作します。XML ファイルの生成方法に問題があるはずですが、何が原因かわかりません。
可能になり次第、この質問に賞金を追加します;)
問題の概要:システムによって生成された XML ファイル (最初のコード ブロック) をプログラムに再度インポートすると (3 番目のコード ブロック)、行と列は表示されますが、すべてのセルが空白になります。