2015-12-01 5 views
1

Мой сценарий: У меня есть класс под названием Person, который я сохраняю в БД с помощью Dapper. На Человеке у меня есть словарь значений, который я сериализую в строку и храню в качестве varchar (MAX).Как использовать множественное отображение Dapper при сопоставлении одного типа с другим?

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

Это, как я сохранить в БД:

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

Это где я пытаюсь прочитать его

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 и люди индивидуальный

Th е второй gridReader терпит неудачу с При использовании API, многоканальные отображения убедитесь, что вы установите splitOn параметров, если у вас есть другие, чем Id ключи \ имя г \ nParameter: splitOn

Я чувствую, что я, возможно, изгиб щеголеватый немного попробовать и сделать его делать то, что он не должен был делать, т. е. чтение строки из БД и десериализация ее в словарь и присвоение Person.Values.

Это способ сделать это (и у меня есть ошибка где-то)? или есть другой подход, который я должен предпринять?

Я использовал это как REF: (Link to approximate location in file at 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 
+0

Исправлены некоторые ошибки, которые, я думаю, могли смутить ад из тех, кто когда-либо пытался это прочитать. – scheepersw

ответ

0

Пытались другие splitOn ы?

У меня нет теста БД с удобством, но я думаю, что splitOn должен быть первым столбцом, который вы хотите в следующем сопоставленном объекте, а не в последнем столбце предыдущего. Также столбцы становятся членами объекта, а не целого значения (хотя может быть исключение для случаев с одним столбцом, опять же, у меня нет тестовой базы данных).

TL; DR - попробовать что-то вроде этого

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

В противном случае, я хотел бы предложить только с помощью dynamic возврата Dapper методов.

+0

Большое спасибо. Это сделал трюк. – scheepersw