Using a static DataSet as DataSource

房东的猫 提交于 2019-12-24 01:10:00

问题


In my application I have a DataSet that holds tables that are used in different forms, all over my application. To be able to maintain concurrency between forms, and not having to get data from the database every time the user opens a new form, I hold my DataSet as a static field in the program class like this:

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());
    }

This makes it pretty easy to use the DataSet programatically. Working in the design-time however causes allot of frustration. For examle; I have a form with a DataGridView bound to a BindingSource. If I want to be able to work with the columns of the DataGridView in design-time, I must have an object of my custom DataSet accessible to the BindingSource in the InitializeComponent.

All workarounds for this I can think of are pretty ugly hacks. Like using a dummy object in Designer.cs to keep the design-time happy, and then assign the static object to the field holding the dummy object. And after that reset all the bindings in in the constructor. This must be considered very bad practice, right?

So my question is this: Isn't there a more elegant, or at least practical approach to this? Or are there any suggested best-practices for working with DataSets in multiple forms?

Edit
Stock refers to stock keeping as in inventory. No heavy processing is done on the data, which is kept on a MySql-database on a local server.


回答1:


Displaying one DataSource at runtime, and other at DesignTime is not ugly at all. I think what you are fighting with is fairly common when using DataTables, DataSets, and DataGridViews and the designer. Its a great tool if are working with very simple Master/Detail forms and don't want step outside of standard behaviors.

In the scenario you have described, you want to alter the normal usage of these items so that you can pre-load the data when the application starts. As you've found out, this causes a few issue that you now have to handle on your own. Part of handling that issue is resetting the DataSource to a new value at runtime. That's not inelegant or bad practice at all.

However, when you start talking about fakes, and caching due to performance concerns, I wonder if you really want a database at all. It seems like you are looking to develop a model (using C# objects) that you can bind to, update, and serialize as needed. While I'm not sure thats true for your design, if it were my design (with my limited understanding of your problem) thats what I would be doing. A database would not be a big part of my project at this point, if at all. I would build C# objects that represent my tables, a model class to manage those items, and a factory to instantiate the model and manage its lifetime.

If, at some point, I had to serialize/interact to/with a database, I would build that into the model.

A bigger question for me in regards to elegance, is how would I test all of this? If I'm binding at design time, and relying on a static to load at run time, then my design has blocked me from performing any sort of unit, or class-based integration tests. If I had separated out the database stuff into a model, then I would have separated the concern of data management into a class that I could stick an interface into, which gives me something to fake or mock and stub.




回答2:


I'd go with the idea of using a dummy object in the Designer.cs but comment the appropriate section using conditional compilation (i.e. #if DEBUG)




回答3:


Try using a singleton design pattern.

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"];
    }

}

Use it like this:

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


来源:https://stackoverflow.com/questions/5142329/using-a-static-dataset-as-datasource

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!