Всем привет. Появилась необходимость работать с данными, которые нужно будет сохранять на жёсткий диск. Решил использовать DataTable и хранить их в виде xml файлов. Таблиц в проге планируется несколько. Решил оформить в отдельный класс, код которого будет ниже. Есть некие общие методы, дублирующиеся для каждой таблицы. Есть для каждой таблицы свои методы. Вот код:
public class Tables
{
public static class Groups
{
// возвращаем всю строку по айди
public static DataRow GetFullRow(int id)
{
return dt.Select("id='" + id.ToString() + "'")[0];
}
public static DataRow GetRow(string query)
{
return dt.Select(query)[0];
}
static string xml_path;
public static DataTable dt;
public static void ReadXml()
{
xml_path = Main.GetXmlPath(dt.TableName);
if (File.Exists(xml_path))
{
dt.ReadXml(xml_path);
}
}
public static void SaveToXml()
{
dt.WriteXml(xml_path);
}
public static void Create()
{
dt = new DataTable("Groups");
dt.Columns.Add("id", typeof(int));
dt.Columns.Add("name", typeof(string));
dt.PrimaryKey = new DataColumn[] { dt.Columns[0] };
dt.Columns[0].AutoIncrement = true;
dt.Columns[0].AutoIncrementStep = 1;
ReadXml();
}
public static void Add(bool save_after, DataRow dr)
{
dt.Rows.Add(dr);
if (save_after)
SaveToXml();
}
}
public static class Items
{
public static void SaveToXml()
{
dt.WriteXml(xml_path);
}
static string xml_path;
public static DataTable dt;
public static void ReadXml()
{
xml_path = Main.GetXmlPath(dt.TableName);
if (File.Exists(xml_path))
{
dt.ReadXml(xml_path);
}
}
public static void Create()
{
dt = new DataTable("Items");
dt.Columns.Add("id", typeof(int));
dt.Columns.Add("name", typeof(string));
dt.Columns.Add("cost", typeof(double));
dt.Columns.Add("id_group", typeof(int));
dt.Columns.Add("is_periodic", typeof(bool));
dt.Columns.Add("date", typeof(string));
dt.Columns.Add("period", typeof(int));
dt.Columns.Add("is_dynamic", typeof(bool));
dt.Columns.Add("calc_type", typeof(int));
dt.Columns.Add("days", typeof(int));
dt.Columns.Add("val_to_multiply", typeof(double));
dt.Columns.Add("payday", typeof(DateTime));
dt.PrimaryKey = new DataColumn[] { dt.Columns[0] };
dt.Columns[0].AutoIncrement = true;
dt.Columns[0].AutoIncrementStep = 1;
ReadXml();
}
// метод добавляет строку в таблицу
// а если такой id уже есть, то изменяет
public static void Add(bool save_after, DataRow dr)
{
dt.Rows.Add(dr);
if (save_after)
SaveToXml();
}
public static void EditRow(bool save_after,DataRow dr,int id)
{
DataRow found = dt.Select("id='" + id.ToString() + "'")[0];
int cnt = found.ItemArray.Count();
for (int i = 1; i < cnt; i++)
{
try
{
found[i] = dr[i];
}
catch { continue; }
}
if (save_after)
SaveToXml();
}
// возвращаем всю строку по айди
public static DataRow GetFullRow(int id)
{
return dt.Select("id='"+id.ToString() + "'")[0];
}
public static DataRow GetRow(string query)
{
return dt.Select(query)[0];
}
public static void RemoveById(bool save_after,int id)
{
dt.Rows.Remove(dt.Select("id='" + id.ToString() + "'")[0]);
if (save_after)
SaveToXml();
}
public static class JobMoney
{
public static void SaveToXml()
{
dt.WriteXml(xml_path);
}
static string xml_path;
public static DataTable dt;
public static void ReadXml()
{
xml_path = Main.GetXmlPath(dt.TableName);
if (File.Exists(xml_path))
{
dt.ReadXml(xml_path);
}
}
public static void Create()
{
dt = new DataTable("JobMoney");
dt.Columns.Add("id", typeof(int));
dt.Columns.Add("date", typeof(int)); // число месяца
dt.Columns.Add("size", typeof(double));
dt.PrimaryKey = new DataColumn[] { dt.Columns[0] };
dt.Columns[0].AutoIncrement = true;
dt.Columns[0].AutoIncrementStep = 1;
ReadXml();
}
// метод добавляет строку в таблицу
// а если такой id уже есть, то изменяет
public static void Add(bool save_after, DataRow dr)
{
dt.Rows.Add(dr);
if (save_after)
SaveToXml();
}
// возвращаем всю строку по айди
public static DataRow GetFullRow(int id)
{
return dt.Select("id='" + id.ToString() + "'")[0];
}
}
public static class Main
{
public static void InitAll()
{
Groups.Create();
Items.Create();
JobMoney.Create();
}
public static string GetXmlPath(string tableName)
{
return String.Format(
"{0}\\{1}.xml", Application.StartupPath,tableName
);
}
}
}
Вопрос в следующем - насколько правильно оформлять работу с таблицами именно таким образом. Каким образом сделать так, чтобы не дублировать одинаковый код для разных таблиц.
сделал так:
public abstract class test
{
protected string Xml_path;
protected DataTable dt { get; set; }
protected test(string tablename)
{
dt = new DataTable();
dt.Columns.Add("id",typeof(int));
dt.Columns.Add("name",typeof(string));
dt.PrimaryKey = new DataColumn[] { dt.Columns[0] };
dt.Columns[0].AutoIncrement = true;
dt.Columns[0].AutoIncrementStep = 1;
dt.TableName = tablename;
Xml_path = Application.StartupPath + "\\" + tablename + ".xml";
}
protected void SavetoXml()
{
dt.WriteXml(Xml_path);
}
protected void ReadXml()
{
if (File.Exists(Xml_path))
{
try
{
dt.ReadXml(Xml_path);
}
catch (Exception ex)
{
string x = ex.Message;
}
}
}
}
public class t1 : test
{
public t1(string tablename) : base(tablename)
{
// добавляем недостающие поля в таблицу
dt.Columns.Add("test");
// грузим данные из xml
ReadXml();
}
public void t1_method()
{
MessageBox.Show("URA!!!");
}
}
public class t2 : test
{
public t2(string tablename) : base(tablename)
{
}
}
public class t3 : test
{
public t3(string tablename) : base(tablename)
{
}
}
Сделай общий класс, а от него уже наследуй отдельные классы для каждой таблицы, и тебе не придётся дублировать код.
Наследование
В вашем коде дублирование убирается приминением паттерна «шаблонный метод».
Решением вашей проблемы является создание базового класса Table
с последующей специализацией наследников до GroupsTable
, ItemsTable
, JobMoneyTable
. Все общие части алгоритма следует перенести в Table
, а те части алгоритма, которые изменяются в зависимости от таблицы — в наследника.
Небольшая статья о наследовании на MSDN
API
У ваших классов (Groups, Items, JobMoney) есть одна общая и очень серьезная проблема. В них нарушается инвариант в зависимости от очередности вызова методов.
Например, что будет, если я напишу следующий код:
Groups.SaveToXml();
До вызова метода Create()
? Ответ — NullReferenceException
так как поле db
ещё не инициализировано. Нужно стараться избегать такого проектирования, при котором корректность инвариантов класса зависит от очередности вызова его методов.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Делаю регистрацию на сайте в учебных целяхХочу запретить создавать пользователей с одинаковым логином
Здравствуйте! Такая проблемаХочу вывести таблицу результатов примитивного вида: Ниже мой недописанный код
Приветствую! Клепаю 2D игрушку на небезызвестном двигателе Unity3DВозник вопрос сразу же после отрисовки первого уровня
Я пишу на C# программу, которая с помощью библиотеки log4net ведет лог в отдельный файлКогда лог-файл переполняется, он должен быть удален