Mein Szenario: Ich habe eine Klasse namens Person, die ich mit Dapper in der DB speichere. Bei Person habe ich ein Dictionary of Values, das ich in eine Zeichenfolge serialisieren und als varchar (MAX) speichern soll.
public class Person
{
public string Name {get; set;}
public int Id {get; set;} //PK in DB
public int Age {get; set;}
public IDictionary<string, string> Values {get; set;}
}
So speichere ich in der DB:
DynamicProperties dp = new DynamicProperties();
dp.Add("Name", p.Name);
dp.Add("Age", p.Age);
dp.Add("Values", Jil.JSON.Serialize<IDictionary<string, string>>(p.Values));
conneciton.Execute(insertSql, dp, commandType: CommandType.StoredProcedure);
Hier versuche ich es zu lesen
private Func<Person, object, Person> GetPerson = new Func<Person, object, Person>
((person, values) => {
person.Values = Jil.JSON.Deserialize<Dictionary<string, string>>((string)values);
return person;
});
string sql = "SELECT text
FROM otherTable
SELECT Name, Id, Age, Values
FROM People
WHERE Id = @Id"
SqlMapper.GridReader gridReader = connToDeviceConfig.QueryMultiple(sql, new {Id = 5}, commandType: CommandType.StoredProcedure);
List<string> listOfOtherStuff = gridReader.Read<string>().ToList();
List<Person> people = gridReader.Read<Person, object, Person>(GetPerson, splitOn: "Age").ToList();
// listOfOtherStuff und Leute sind getrennt
Der zweite GridReader schlägt fehl Bei der Verwendung der Multi-Mapping-APIs stellen Sie sicher, dass Sie den splitOn-Parameter festlegen, wenn Sie andere Schlüssel als Id \ r \ nParametername: splitOn haben
Ich habe das Gefühl, dass ich Dapper vielleicht etwas verbiege, um etwas zu tun, was es nicht tun sollte, dh eine Zeichenkette aus der DB auszulesen und sie in ein Dictionary zu deserialisieren und Personen.Values zuzuweisen.
Ist das der Weg (und ich habe irgendwo einen Fehler)? Oder gibt es einen anderen Ansatz, den ich nehmen sollte?
Ich habe dies als Referenz verwendet: (Link zum ungefähren Speicherort in der Datei auf Archive.org)
public void TestProcSupport()
{
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);
connection.Execute(@"create proc #TestProc
@a int,
@b int output
as
begin
set @b = 999
select 1111
return @a
end");
connection.Query<int>("#TestProc", p, commandType: CommandType.StoredProcedure).First().IsEqualTo(1111);
p.Get<int>("c").IsEqualTo(11);
p.Get<int>("b").IsEqualTo(999);
}
StackTrace:
at Dapper.SqlMapper.GetNextSplit(Int32 startIdx, String splitOn, IDataReader reader) in D:\Dev\dapper-dot-net\Dapper NET40\SqlMapper.cs:line 2111
at Dapper.SqlMapper.GenerateDeserializers(Type[] types, String splitOn, IDataReader reader) in D:\Dev\dapper-dot-net\Dapper NET40\SqlMapper.cs:line 2057
at Dapper.SqlMapper.<MultiMapImpl>d__71`8.MoveNext() in D:\Dev\dapper-dot-net\Dapper NET40\SqlMapper.cs:line 1857
at Dapper.SqlMapper.GridReader.<MultiReadInternal>d__9`8.MoveNext() in D:\Dev\dapper-dot-net\Dapper NET40\SqlMapper.cs:line 4300
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at Dapper.SqlMapper.GridReader.Read[TFirst,TSecond,TReturn](Func`3 func, String splitOn, Boolean buffered) in D:\Dev\dapper-dot-net\Dapper NET40\SqlMapper.cs:line 4330
Versuchte andere splitOn
s?
Ich habe keinen DB-Test mit handy, aber ich denke, splitOn soll die erste Spalte sein, die Sie im nächsten gemappten Objekt haben wollen, nicht die letzte Spalte im vorherigen. Außerdem werden die Spalten Mitglieder eines Objekts, nicht der ganze Wert (obwohl es eine Ausnahme für Fälle mit einer Spalte geben kann, habe ich wiederum keine Test-DB zur Hand).
TL, DR - versuche so etwas
class ValuesObj{
public string Values {get;set;}
}
// whatever code here
private Func<Position, ValuesObj, Position> GetPerson = new Func<Person, ValuesObj, Person>
((person, valuesObj) => {
string values = valuesObj.Values;
person.Values = Jil.JSON.Deserialize<Dictionary<string, string>>((string)values);
return position;
});
string sql = "SELECT text
FROM otherTable
SELECT Name, Id, Age, Values
FROM People
WHERE Id = @Id"
SqlMapper.GridReader gridReader = connToDeviceConfig.QueryMultiple(sql, new {Id = 5}, commandType: CommandType.StoredProcedure);
List<string> listOfOtherStuff = gridReader.Read<string>().ToList();
List<Person> people = gridReader.Read<Person, ValuesObj, Person>(GetPerson, splitOn: "Values").ToList();
Ansonsten würde ich vorschlagen, nur die dynamic
Return-Dapper-Methoden zu verwenden.