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

现在如您所见,我正在tableNameType传递给我的对象中获取。在我们的示例中是Foo. 此外,我正在收集要通过反射插入的字段列表。但是,相处中的障碍是Dapper需要将对象发送给它以获取参数值。现在,如果我不需要提供DataId类型的属性,我可以传入给我的对象,但我需要该DataId属性,以便我可以正确关联日志。

我在问什么?

  1. 我将不得不创建一个动态类型还是可以Dapper做其他事情来提供帮助?
  2. 如果我必须创建一个动态类型,有没有比使用TypeBuilder? 我以前做过,可以再做一次,但是男人很痛苦。
  3. 如果我将不得不使用TypeBuilder我会对您的示例感兴趣,因为您可能知道比我更有效的方法。因此,如果您有一些想法,请举一个例子。

免责声明

在上面的代码示例中,您会看到我尝试传入 aDictionary<string, object>Dapper不接受。我几乎知道它不会,因为我已经看过源代码,但我只是希望我错过了一些东西。

谢谢大家!

4

2 回答 2

3

Dapper 中有一个 BuiltIn 类型来传递参数,哪些属性仅在运行时是已知的:检查 class 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

我知道你问过关于 dapper 但...

Sauce DB 实际上很好地处理了这种类型的场景。有几种方法可以做到这一点。下面是一些说明它的示例代码。注意:您可以覆盖如何找到表名,并且如果您愿意,可以使用一些方法来检索解析的表名。

免责声明:我写了 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 回答