Использование статического набора данных в качестве источника данных

В моем приложении у меня есть DataSet, который содержит таблицы, которые используются в разных формах, по всему моему приложению. Чтобы поддерживать параллелизм между формами и не получать данные из базы данных каждый раз, когда пользователь открывает новую форму, я храню свой DataSet как статическое поле в классе программы, например:

static class Program
{
    public static CustomDataSet StockDataSet { get; private set; }

    [STAThread]
    static void Main()
    {
        StockDataSet = new Database.CustomDataSet();
        StockDataSet.InitRelations();
        StockDataSet.EnforceConstraints = false;
        StockDataSet.Categories.Fill();
        StockDataSet.Suppliers.Fill();
        StockDataSet.StockItems.Fill();
        StockDataSet.EnforceConstraints = true;

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new MainWindow());
    }

Это позволяет довольно просто использовать DataSet программно. Работа во время разработки, однако, вызывает много разочарований. Для экзамена; У меня есть форма с DataGridView, связанной с BindingSource. Если я хочу иметь возможность работать со столбцами DataGridView во время разработки, у меня должен быть объект моего пользовательского набора данных, доступный для BindingSource в InitializeComponent.

Все обходные пути для этого, я могу придумать, довольно уродливые хаки. Например, использование фиктивного объекта в Designer.cs для поддержания времени разработки, а затем назначение статического объекта полю, содержащему фиктивный объект. И после этого сбросьте все привязки в конструкторе. Это должно считаться очень плохой практикой, верно?

Поэтому мой вопрос заключается в следующем: нет ли более элегантного или хотя бы практического подхода к этому? Или есть какие-либо рекомендации по работе с наборами данных в нескольких формах?

редактировать
Запас относится к хранению как в инвентаре. Не выполняется никакой тяжелой обработки данных, которые хранятся в базе данных MySql на локальном сервере.

3 ответа

Решение

Отображение одного источника данных во время выполнения, а другого в DesignTime совсем не страшно. Я думаю, что то, с чем вы боретесь, довольно распространено, когда используются DataTables, DataSets, DataGridViews и дизайнер. Это отличный инструмент, если вы работаете с очень простыми формами Master/Detail и не хотите выходить за рамки стандартного поведения.

В описанном вами сценарии вы хотите изменить обычное использование этих элементов, чтобы вы могли предварительно загружать данные при запуске приложения. Как вы узнали, это вызывает некоторые проблемы, с которыми вам теперь придется справиться самостоятельно. Частью решения этой проблемы является сброс DataSource к новому значению во время выполнения. Это совсем не безумие или плохая практика.

Однако, когда вы начинаете говорить о подделках и кешировании из-за проблем с производительностью, я задаюсь вопросом, действительно ли вам нужна база данных вообще. Похоже, вы хотите разработать модель (используя объекты C#), которую вы можете привязывать, обновлять и сериализовать по мере необходимости. Хотя я не уверен, что это верно для вашего дизайна, если бы это был мой дизайн (с моим ограниченным пониманием вашей проблемы), это было бы то, чем я бы занимался. База данных не будет большой частью моего проекта на данный момент, если вообще. Я бы построил объекты C#, которые представляют мои таблицы, класс модели для управления этими элементами и фабрику для создания экземпляра модели и управления ее временем жизни.

Если бы в какой-то момент мне пришлось сериализовать / взаимодействовать с / с базой данных, я бы встроил это в модель.

Более важный вопрос для меня в отношении элегантности: как бы я все это проверил? Если я привязываюсь во время разработки и полагаюсь на статическую загрузку во время выполнения, тогда моя конструкция не позволяет мне выполнять какие-либо модульные или интеграционные тесты на основе классов. Если бы я разделил содержимое базы данных на модель, то я бы разделил заботу об управлении данными на класс, в который я мог бы вставить интерфейс, что давало бы мне что-то подделать или посмеяться и заглушить.

Попробуйте использовать шаблон дизайна Singleton.

public sealed class DB
{
    private static readonly DB instance = new DB( );
    public static DB Instance { get { return instance; } }

    static DB( ) { }
    private DB( ) 
    {
        StaticData = new DataSet( );
    }

    private static DataSet StaticData;

    public DataTable GetCategoryTable( )
    {
        // check if the table has been created
        if( StaticData.Tables["Category"] == null )
        {
            // build table (or retrieve from database)
            DataTable table = new DataTable( );
            table.TableName = "Category";
            table.Columns.Add( "ID", typeof( int ) );
            table.Columns.Add( "Name", typeof( string ) );
            table.Columns.Add( "Description", typeof( string ) );

            table.Rows.Add( 1, "Beverages", "Soft drinks, coffees, teas, beers, and ales" );
            table.Rows.Add( 2, "Condiments", "Sweet and savory sauces, relishes, spreads, and seasonings" );
            table.Rows.Add( 3, "Produce", "Dried fruit and bean curd" );
            table.Rows.Add( 4, "Seafood", "Seaweed and fish" );
            table.Rows.Add( 5, "Meat/Poultry", "Prepared meats" );
            StaticData.Tables.Add(table.Copy());

        }
        return StaticData.Tables["Category"];   
    }

    public DataTable GetStatusTable( )
    {
        // check if the table has been created
        if( StaticData.Tables["Status"] == null )
        {
            // build table (or retrieve from database)
            DataTable table = new DataTable( );
            table.TableName = "Status";
            table.Columns.Add( "ID", typeof( int ) );
            table.Columns.Add( "Name", typeof( string ) );
            table.Columns.Add( "Description", typeof( string ) );

            table.Rows.Add( 1, "Active", "Active" );
            table.Rows.Add( 2, "Retired", "Retired" );
            StaticData.Tables.Add( table.Copy( ) );

        }
        return StaticData.Tables["Status"];
    }

}

Используйте это так:

    private void Form1_Load( object sender, EventArgs e )
    {
        DB db = DB.Instance;
        dataGridView1.DataSource = db.GetCategoryTable( );
        dataGridView2.DataSource = db.GetCategoryTable( );
        dataGridView3.DataSource = db.GetStatusTable( );
    }

Я хотел бы пойти с идеей использования фиктивного объекта в Designer.cs, но прокомментировать соответствующий раздел, используя условную компиляцию (т.е. #if DEBUG)

Другие вопросы по тегам