简体   繁体   中英

Generic function for reading data from SQL Server

Lets say I have two classes which look like these.

class Foo1
{
   public String P1 { get; set; }
   public String P2 { get; set; }
}

class Foo2
{
   public String P3 { get; set; }
   public String P4 { get; set; }
}

P1, P2, P3 and P4 are in no way related. Same with Foo1 and Foo2 . They represent totally different objects.

I have two database tables which have a list of Foo1 and Foo2 objects. I have to create a List<Foo1> and List<Foo2>

The input for the stored procedures which return the Foo1's and Foo2's are different.

Here is my problem - I want to create a generic function that would connect to database and fetch either Foo1 or Foo2 list as I wish

Initially I thought of something like this

internal static SqlDataReader GetData(String Proc,NameValueCollection InputParams,SqlConnection conn, ref String Err)
{

    using (SqlCommand cmd = conn.CreateCommand())
    {
        try
        {
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.CommandText = Proc;
            conn.Open();

            SqlCommandBuilder.DeriveParameters(cmd);


            foreach (SqlParameter p in cmd.Parameters)
            {
                if (p.Direction == ParameterDirection.Input)
                {

                    if (InputParams[p.ParameterName.ToLower().Substring(1)] != String.Empty)
                    {
                        p.Value = InputParams[p.ParameterName.ToLower().Substring(1)];
                        p.DbType = DbType.AnsiString;
                    }
                    else
                    {
                        Err += "<argumentnotfound>" + p.ParameterName + "</argumentnotfound>";                                    
                    }
                }
                else p.Value = DBNull.Value;

            }
            return cmd.ExecuteReader();
        }
        catch (Exception e)
        {
            return null;
        }       
    }   
} 

I didn't like the idea of returning SqlDataReader or creating and closing SqlConnection outside this function.

Ideally, I would like to iterate through "reader" object inside this function but return either List<Foo1> or List<Foo2> . One solution i can think of is this

        internal static List<Object> GetData(NameValueCollection InputParams, ref String Err, String ClassName, String Proc)
{
    List<Object> [] objectlist = new List<Object>();
    using (SqlConnection conn = getConnection())
    {
        using (SqlCommand cmd = conn.CreateCommand())
        {
            try
            {
                /*
                    ~~ Same as before
                */
                SqlDataReader reader =  cmd.ExecuteReader();
                while(reader.Read())
                {

                    if(ClassName == "Foo1")
                    {
                        Foo1 f = new Foo1();
                        f.P1 = reader["p1"].ToString();
                        objectList.Add(f1);
                    }
                    else if(ClassName == "Foo2")
                    {
                        /* Create and initialize Foo2 object*/
                        objectList.Add(f2);
                    }


                }
                return objectList;
            }
            catch (Exception e)
            {

            }
            finally
            {
                conn.Close();
            }
        }
    }

    return null;
}

Is there a better/elegant approach?

Edit

What I forgot to mention is this - My final objective is to create JSON for AJAX calls from Javascript. My plan was to iterate over Foo1 and Foo2 object lists to create Json data for each request.

I think that I can create JSON inside the stored procedures and return it as a varchar(max) and use JSON2.js to create JSOn objects on the client side. The downside I see here is the limit of 8000 char limit on the varchar.

I don't think you're going to buy much trying to genericize this. The only pieces that are truly common between the procedures to create Foo1 and Foo2 are creating/closing the Connection and DataReader . They are going to have different SQL commands and different mappings between the DataReader and the class.

My advice would be to either use a library like NHibernate or Entity Framework that already abstracts away the database grunge, or abstract away those parts and have factories that create Foo1 and Foo2 instances from a DataReader . Otherwise you're going to end up with a bunch of switches that change the code based on the type of object you're trying to create (which is the road you are headed down) or using reflection to automatically map properties to database columns.

I'm not an expert unfortunately, but I think I get what you're trying to do. My advise (though it may not be the best) would be to create an Enum of the data types, then search it for a submission in the generic function, then you can use the tablename against a string which you've inputted.

I use a similar method for storing information of this nature, it looks like this...

Function:

    public UInt32 getKeyCode(string Key)
    {
        Constants.KeyboardControls keynum;
        if (Enum.TryParse<Constants.KeyboardControls>(Key, true, out keynum))
        {
            return (UInt32)(keynum);
        }
        else
        {
            return new UInt32();
        }
    }

Enumeration:

    public enum KeyboardControls : uint
    {
        F1 = 0x70,
        F2 = 0x71,
        F3 = 0x72,
        F4 = 0x73,
        F5 = 0x74,
        F6 = 0x75,
        F7 = 0x76,
        F8 = 0x77,
        F9 = 0x78,
        F10 = 0x79,
        F11 = 0x7A,
        F12 = 0x7B,
        left = 0x25,
        up = 0x26,
        right = 0x27,
        down = 0x28
    }

I hope this helps at least a bit, you can list any object in an enum, just change where it says uint to your object type, and the left side is pretty much strings.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM