0

これらのように見える2つのクラスがあるとしましょう。

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、および P4はまったく関係ありません。Foo1およびFoo2と同じです。それらはまったく異なるオブジェクトを表しています。

Foo1 および Foo2 オブジェクトのリストを持つ 2 つのデータベース テーブルがあります。とを作成する必要が List<Foo1>ありますList<Foo2>

Foo1 と Foo2 を返すストアド プロシージャの入力は異なります。

ここに私の問題があります-データベースに接続し、必要に応じてFoo1またはFoo2リストを取得する汎用関数を作成したい

最初はこんなものを考えていました

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

SqlDataReader を返したり、この関数の外側で SqlConnection を作成して閉じたりするという考えは好きではありませんでした。

理想的には、この関数内の「リーダー」オブジェクトを反復処理したいのですが、またはのいずれList<Foo1>かを返しますList<Foo2>。私が考えることができる1つの解決策はこれです

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

より良い/エレガントなアプローチはありますか?

編集

私が言及するのを忘れていたのはこれです - 私の最終的な目的は、Javascript からAJAX呼び出し用のJSONを作成することです。私の計画は、Foo1 と Foo2 のオブジェクト リストを繰り返し処理して、各リクエストの Json データを作成することでした。

ストアド プロシージャ内で JSON を作成し、それを varchar(max) として返し、JSON2.js を使用してクライアント側で JSOn オブジェクトを作成できると思います。ここで見られる欠点は、varchar の 8000 文字の制限です。

4

2 に答える 2

2

これを一般化しようとして、あまり購入するつもりはないと思います。createFoo1との手順の間で真に共通しているのは、とFoo2の作成/終了のみです。それらは、とクラスの間で異なる SQL コマンドと異なるマッピングを持つことになります。ConnectionDataReaderDataReader

私のアドバイスは、NHibernate や Entity Framework などのデータベース グランジを既に抽象化しているライブラリを使用するか、それらの部分を抽象化Foo1Foo2DataReader. そうしないと、作成しようとしているオブジェクトのタイプに基づいてコードを変更する (これはあなたが向かっている道です) か、リフレクションを使用してプロパティをデータベース列に自動的にマップする一連のスイッチになってしまいます。

于 2013-02-15T23:14:53.107 に答える
0

残念ながら私は専門家ではありませんが、あなたがやろうとしていることは理解できると思います。私のアドバイス (最善ではないかもしれませんが) は、データ型の Enum を作成し、ジェネリック関数で送信を検索してから、入力した文字列に対して tablename を使用することです。

私はこの性質の情報を保存するために同様の方法を使用しています。それは次のようになります...

関数:

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

列挙:

    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
    }

これが少なくとも少し役立つことを願っています。列挙型に任意のオブジェクトをリストできます。uint と表示されている場所をオブジェクトタイプに変更するだけで、左側はほとんど文字列です。

于 2013-02-15T23:06:57.147 に答える