Créer un type dynamique en C # pour Dapper

c# dapper

Question

J'ai une application dans laquelle je sauvegarde des données structurées inconnues. Donc, supposons un instant qu'il y ait une table dans la base de données nommée Foo et qu'elle ressemble à ceci:

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])
)

Et Foo est lié à une table nommée Data qui va stocker le fournisseur qui a enregistré les données ainsi que la date et l'heure de son enregistrement, et disons que cette table ressemble à ceci:

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])
)

Bon, supposons maintenant que le fournisseur (que je ne connais pas les données qu'il fournit) a une classe nommée Foo qui ressemble à ceci:

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

Donc, lorsque le fournisseur m'envoie une instance de Foo je vais l'interroger et déterminer la table dans la base de données dans laquelle il doit être inséré, et supposons que le bloc de code ressemble à ceci:

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

Maintenant, comme vous pouvez le voir, tableName la tableName partir du Type d'objet qui m'a été transmis. Dans notre exemple, c'est Foo . De plus, je recueille la liste des champs à insérer avec réflexion. Cependant, le problème réside dans le fait que Dapper requiert qu'un objet lui soit envoyé pour les valeurs des paramètres. Maintenant, si je n'avais pas besoin de fournir la propriété DataId sur le type, je pourrais simplement passer l'objet qui m'a été donné, mais j'ai besoin de cette propriété DataId pour pouvoir relier le journal correctement.

Qu'est-ce que je demande?

  1. Dois-je créer un type dynamique ou Dapper peut-il faire autre chose pour aider?
  2. Si je dois créer un type dynamique, y a-t-il un moyen plus simple d'utiliser TypeBuilder ? Je l'ai déjà fait et je peux le refaire, mais l'homme est pénible.
  3. Si je dois utiliser TypeBuilder je serais intéressé par votre exemple car vous connaissez peut-être un moyen plus efficace que moi. Veuillez donc inclure un exemple si vous avez des idées.

AVERTISSEMENT

Dans l'exemple de code ci-dessus, vous voyez que j'ai essayé de passer un Dictionary<string, object> place, mais Dapper ne l'accepte pas. Je savais à peu près que ce ne serait pas parce que j'avais déjà regardé le code source, mais j'espérais juste avoir raté quelque chose.

Merci a tous!

Réponse acceptée

Il existe un type BuiltIn dans Dapper pour transmettre le paramètre dont les propriétés sont connues uniquement à l'exécution: vérifiez la classe DynamicParameters . Il est utilisé comme:

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

puis transmis comme objet paramètre à la méthode Execute . Il est généralement utilisé avec SP (vous pouvez donc également l'utiliser pour lire les valeurs de sortie), mais il n'y a aucune raison pour qu'il ne fonctionne pas avec les requêtes SELECT / INSERT / UPDATE standard.


Réponse populaire

Je sais que vous avez posé des questions sur Dapper mais ...

Sauce DB gère très bien ce type de scénario. Il y a plusieurs façons de le faire. Vous trouverez ci-dessous un exemple de code qui l'illustre. Remarque: vous pouvez remplacer la manière dont le nom de la table est trouvé et il existe des méthodes qui vous permettent de récupérer le nom de la table résolue si vous le souhaitez.

Disclamer: J'ai écrit 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/




Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi