Frage
Wir haben eine Dapper-Zeile als Ergebnis einer Dapper-Abfrage, die ich als JSON-Zeichenfolge in unserer Datenbank speichern möchte. Leider kann ich das nicht zum Laufen bringen. Beginnen wir also mit einigen Hintergrundinformationen.
Hintergrundinformation
Wir machen ein Projekt, in dem wir Tabellennamen aus einer Tabelle extrahieren, um zu wissen, an welche Tabellen wir uns wenden müssen. Wir möchten auch, dass dies so flexibel wie möglich ist, und haben uns daher entschieden, kein bestimmtes POCO für unsere Daten zu verwenden.
Wir verwenden SQL Server 2014, daher haben wir leider noch keine Option 'FOR JSON'.
Code
Unser Code sieht ungefähr so aus, wobei GetData unsere eigentliche Abfrage ist:
var data = _queryHandler.Handle(new GetData(tableName.ToString(), 0), database);
Das Handle verbindet sich technisch nur mit der Datenbank und ruft auf
conn.QueryAsync(query, parameters)
GetData sieht folgendermaßen aus (vereinfacht):
EXEC ('SELECT * FROM ' + @table + ')'
Argumentation
Da sich der Tabellenname jedes Mal ändert, möchten wir keinen POCO für die Ausgabe erzwingen. Manchmal ist es ein Benutzer, manchmal eine Rolle, es gibt also keine Vorhersage, welche Ausgabe er zurückgibt.
Ergebnisse
Das funktioniert gut. Wir können die Daten in unserer Variablen extrahieren und dies sieht aus wie eine IEnumerable, was in Ordnung sein sollte. Ich nehme an, wir können sie einfach in einer Schleife lesen und die Zeilen extrahieren. Bisher kein Problem.
Das Problem zur Hand
Das nächste, was wir tun möchten, ist, die Daten aus der DapperRow in eine Json-Zeichenfolge zu konvertieren. Es scheint jedoch nicht möglich zu sein, dass sich die Daten wie eine Json-Zeichenfolge verhalten, da JsonConvert.SerializeObject kläglich fehlschlägt. Die DapperRow sieht so aus (nochmals vereinfacht).
{{DapperRow, Id = '07501399-b385-4d8e-bacc-gad9d04c35f7', UserName = 'test8', ApplicationId = '4721fafb-12e6-4e3c-9298-etd82d18a0cb', IsApproved = 'True', IsLockedOut = 'False', CreateDate = '26-3-2019 07:52:55' }}
Ich habe mir bereits Dinge wie den SqlMapper.ITypeHandler
, komme aber immer noch nicht dahin. Zum Beispiel stecke ich mit dem TypeHandler auf dem destinationType fest, da ich keinen bestimmten Typ möchte - naja, mit Ausnahme eines json-Objekts. Aber das ist kein akzeptierter Typ.
public class JsonObjectTypeHandler : SqlMapper.ITypeHandler
{
public void SetValue(IDbDataParameter parameter, object value)
{
parameter.Value = (value == null)
? (object)DBNull.Value
: JsonConvert.SerializeObject(value);
parameter.DbType = DbType.String;
}
public object Parse(Type destinationType, object value)
{
return JsonConvert.DeserializeObject(value.ToString(), destinationType);
}
}
Das einzige andere, was mir in den Sinn kommt, ist, jede einzelne Spalte zu extrahieren und daraus ein Typobjekt zu erstellen, aber wie gesagt, wir möchten kein Modell / Typ für die Daten verwenden, da wir sie flexibel halten möchten .
Könnte mich jemand in die richtige Richtung weisen? Ich habe das Gefühl, etwas Einfaches zu übersehen.
Wenn Sie die nicht typisierte Query
API verwenden, ist jede zurückgegebene Zeile auch ein IDictionary<string,object>
(zusätzlich zur dynamic
API), das in der Regel mit JsonConvert
. Zum Beispiel funktioniert Folgendes für mich:
var tables = (from row in await conn.QueryAsync("select top 5 * from sys.tables")
select (IDictionary<string, object>)row).AsList();
var json = JsonConvert.SerializeObject(tables, Formatting.Indented);
System.Console.WriteLine(json);
Ausgabe:
[
{
"name": "spt_fallback_db",
"object_id": 117575457,
"principal_id": null,
"schema_id": 1,
"parent_object_id": 0,
"type": "U ",
"type_desc": "USER_TABLE",
"create_date": "2003-04-08T09:18:01.557",
"modify_date": "2017-08-22T19:40:40.763",
"is_ms_shipped": true,
"is_published": false,
"is_schema_published": false,
"lob_data_space_id": 0,
"filestream_data_space_id": null,
"max_column_id_used": 8,
... etc