1

未知の構造化データを保存しているアプリケーションがあります。Fooしたがって、データベースにという名前のテーブルがあり、次のようになっていると仮定します。

CREATE TABLE [dbo].[Foo]
(
    [Id] INT NOT NULL PRIMARY KEY IDENTITY, 
    [DataId] INT NOT NULL, 
    [Bar] VARCHAR(50) NOT NULL, 
    CONSTRAINT [FK_Foo_Data] FOREIGN KEY ([DataId]) REFERENCES [Data]([Id])
)

また、データをログに記録したプロバイダーと、ログに記録された日時を格納するFooという名前のテーブルに関連してDataいます。このテーブルは次のようになります。

CREATE TABLE [dbo].[Data]
(
    [Id] INT NOT NULL PRIMARY KEY IDENTITY, 
    [ProviderId] INT NOT NULL, 
    [RecordDateTime] DATETIME NOT NULL, 
    CONSTRAINT [FK_Data_Provider] FOREIGN KEY ([ProviderId]) REFERENCES [Provider]([Id])
)

Fooさて、プロバイダー(私はそれが提供するデータについての知識がありません)が次のような名前のクラスを持っていると仮定しましょう:

[Serializable]
public class Foo : ISerializable
{
    private string bar;

    public string Bar
    {
        get { return bar; }
        set { bar = value; }
    }

    public Foo()
    {
        Bar = "Hello World!";
    }

    public Foo(SerializationInfo info, StreamingContext context)
    {
        this.bar = info.GetString("Bar");
    } 

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("Bar", bar);
    }
}

したがって、プロバイダーからインスタンスが送信されたら、Fooそれを調べて、データベース内のどのテーブルに挿入するかを決定し、コードブロックが次のようになっていると仮定します。

this.connection.Open();

try
{
    var parameters = new
        {
            ProviderId = registeredProvidersIdBySession[providerKey.ToString()],
            RecordDateTime = DateTime.Now,
        };

    var id = connection.Query<int>("INSERT INTO Data (ProviderId, RecordDateTime) VALUES (@ProviderId, @RecordDateTime); SELECT CAST(SCOPE_IDENTITY() as INT)", parameters).Single();

    var t = data.GetType();
    var fields = t.GetProperties(BindingFlags.Public | BindingFlags.Instance);

    var tableName = string.Format("[{0}]", t.Name);
    var fieldList = string.Join(", ", fields.Select(p => string.Format("[{0}]", p.Name)).ToArray());

    var valueList = fields.Select(p => string.Format("@{0}", p.Name)).ToList();
    valueList.Insert(0, "@DataId");

    var values = new Dictionary<string, object>();
    values.Add("@DataId", id);
    foreach (var propertyInfo in fields)
    {
        values.Add(string.Format("@{0}", propertyInfo.Name), propertyInfo.GetValue(data, null));
    }

    return connection.Execute(string.Format(
        "INSERT INTO {0} ({1}) VALUES ({2})",
            tableName,
            fieldList,
            string.Join(", ", valueList.ToArray())), values);
}
finally
{
    this.connection.Close();
}

ご覧のとおり、渡されたオブジェクトのtableNameから取得しています。Typeこの例では、それはFooです。さらに、リフレクションで挿入するフィールドのリストを収集しています。ただし、問題はDapper、パラメータ値のためにオブジェクトを送信する必要があることです。さて、型のプロパティを提供する必要がない場合は、DataId与えられたオブジェクトを渡すだけでDataId済みますが、ログを正しく関連付けることができるように、そのプロパティが必要です。

私は何を求めていますか?

  1. 動的タイプを作成する必要がDapperありますか、それとも何か他のことをすることができますか?
  2. 動的型を作成する必要がある場合、?を使用するよりも簡単な方法はありTypeBuilderますか?私は前にそれをしました、そして再びそれをすることができます、しかし人それは苦痛です。
  3. 私が使用するTypeBuilder必要がある場合は、私よりも効率的な方法を知っているかもしれないので、あなたの例に興味があります。それで、あなたがいくつかの考えを持っているならば、例を含めてください。

免責事項

Dictionary<string, object>上記のコード例では、代わりに渡そうとしましたが、Dapperそれを受け入れません。すでにソースコードを見ていたので、そうはならないとは思っていましたが、何かを見逃したいと思っていました。

皆さんありがとう!

4

2 に答える 2

3

Dapperには、実行時にのみ既知のプロパティであるパラメータを渡すための組み込み型があります。クラスを確認してくださいDynamicParameters。それは次のように使用されます:

var p = new DynamicParameters();
p.Add("@a", 11);
p.Add("@b", dbType: DbType.Int32, direction: ParameterDirection.Output);
p.Add("@c", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue);

次に、パラメータオブジェクトとしてExecuteメソッドに渡されます。これは通常SPで使用されます(したがって、出力値の読み取りにも使用できます)が、通常のSELECT / INSERT/UPDATEクエリでの動作を妨げる理由はありません。

于 2012-09-20T15:35:51.577 に答える
1

あなたがダッパーについて尋ねたのは知っていますが...

Sauce DBは、実際にはこのタイプのシナリオをかなりうまく処理します。あなたがそれをすることができるいくつかの方法があります。以下はそれを説明するいくつかのサンプルコードです。注:テーブル名の検索方法をオーバーライドできます。必要に応じて、解決されたテーブル名を取得できるメソッドがあります。

Disclamer:SauceDBを書きました

public class Foo
{
    public int ID { get; set; }
    publi string Name { get; set; }
}

public class Bar
{
    public int ID { get; set; }
    publi string Name { get; set; }
}

public class  MainClass
{
    IDataStore _dstore;
    public void Main()
    {
        _dstore = new SqlServerDataStore("my_connection_string")//create data store

        InsertObject(new Foo());
        InsertObject(new Bar());
    }

    public void InsertObject(object o)
    {
        //this will assume the table it belongs to is the type name + an s
            //you can override the table name behavior as well
        _dstore.InsertObject(o);
    }
}

http://sauce.codeplex.com/

于 2012-09-20T15:46:01.107 に答える