2016-06-15 2 views
1

У меня есть проект, который не позволяет нам изменять SPROCS, но я хотел использовать что-то, чтобы автоматически сопоставлять строки datareader с классом POCO. Пришел Даппер на помощь. По большей части он отлично работает, но в некоторых случаях, когда мне нужно заполнять вложенные классы. Например, у меня есть эта модельDapper, выражения Lambda и возвращаемые правильные отображаемые поля

public class Account 
{ 
    public string AccountNumber { get; set; } 

    /* Removed for brevity */ 

    public Contact Contact { get; set; } 
} 

public class Contact 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
} 

мой respository просто выглядел так:

/// <summary> 
/// Lists a range of items 
/// </summary> 
/// <param name="storedProcedureName">The name of the SPROC to execute</param> 
/// <param name="parameters">The parameters needed for the SPROC</param> 
/// <returns></returns> 
public async Task<IList<T>> ListAsync(string storedProcedureName, OracleDynamicParameters parameters = null) 
{ 
    return await ExecuteReaderAsync(storedProcedureName, parameters); 
} 

/// <summary> 
/// Private method for executing a reader and returning the results as a list 
/// </summary> 
/// <param name="storedProcedureName">The name of the SPROC to execute</param> 
/// <param name="parameters">The parameters needed for the SPROC</param> 
/// <returns></returns> 
private async Task<IList<T>> ExecuteReaderAsync(string storedProcedureName, OracleDynamicParameters parameters = null) 
{ 

    // Init command 
    InitializeCommand(storedProcedureName, parameters); 

    // Dynamically populate our list 
    var list = await this._connection.QueryAsync<T>(storedProcedureName, parameters, commandType: CommandType.StoredProcedure); 

    // Dispose 
    DisposeCommand(); 

    // Return our list 
    return list.ToList(); 
} 

, который может быть вызван из любого сервиса немного как это:

return await Repository.ListAsync("IBPA_ORDERS.readLines", parameters); 

Как я сказал, что это отлично подходит для класса POCO без дочерних классов, но, как вы можете видеть, модель имеет Контакт. Видимо, вы можете получить контакт населенный используя лямбды-выражение как это:

.Select(x => new Account 
{ 
    AccountNumber = x.AccountNumber 
    Contact = new Contact 
    { 
     FirstName = x.Firstname, 
     LastName = x.LastName 
    } 
}); 

Итак, я пытаюсь обновить мой Repository метод для обработки этого. До сих пор у меня есть это:

/// <summary> 
/// Private method for executing a reader and returning the results as a list 
/// </summary> 
/// <param name="storedProcedureName">The name of the SPROC to execute</param> 
/// <param name="parameters">The parameters needed for the SPROC</param> 
/// <returns></returns> 
private async Task<IList<T>> ExecuteReaderAsync(string storedProcedureName, OracleDynamicParameters parameters = null, Func<dynamic, T> query = null) 
{ 

    // Init command 
    InitializeCommand(storedProcedureName, parameters); 

    // Get our models 
    var models = await this._connection.QueryAsync(storedProcedureName, parameters, commandType: CommandType.StoredProcedure); 

    // If we supply a query, use it. Otherwise cast the result as our type 
    var results = query == null ? models.Select(m => (T)m) : models.Select(query); 

    // Dispose 
    DisposeCommand(); 

    // Return our list 
    return results.ToList(); 
} 

Но я не уверен, что это правильно. Я попытался назвать это так:

// Execute and return our acctuons 
return await Repository.ListAsync("IBPA_ACCOUNTSS.LIST", parameters, m => new Account { 
    // LineRef = /* m is dynamic */ 
}); 

Поскольку м динамична, я не могу фактически назначать любые свойства.

Может кто-нибудь помочь мне?

+0

Должен ли 'ExecuteReaderAsync' выглядеть как' ExecuteReaderAsync '? Насколько я могу судить, глядя на это, он должен работать. Когда вы говорите, что пытаетесь позвонить, что вы имеете в виду? У вас есть пример? –

+0

обновил мой вопрос, чтобы объяснить проблему немного больше – r3plica

ответ

0

я мог бы быть немного смущен, но я думаю, , что вы спрашиваете, если вы можете иметь Щеголеватый выполнять десериализации, так что Account.Contact правильно заселен.

Если возвращаемые столбцы упорядочены таким образом, что все Account свойств являются первым, и все Contact свойств следуют, то вы можете использовать функцию Multi Mapping щеголеватой в.

Например:

Func<Account, Contact, Account> map = (a, c) => { a.Contact = c; return a; }; 

var results = conn.Query<Account, Contact, Account>(
    sql: storedProcedureName, 
    map: map, 
    splitOn: "FirstName", 
    param: parameters, 
    commandType: CommandType.StoredProcedure); 

В приведенном выше коде, Щеголеватый ожидает, чтобы начать с deserialiazing в Account. Затем, когда он достигнет столбца с именем «FirstName», он начнет десериализацию в Contact. Как только это будет сделано, он вызовет map, который объединит все десериализованные типы в одно единственное возвращаемое значение (Account).

Тип аргументов можно рассматривать как: <DeserializeType1, DeserializeType2, ..., ReturnType>.

Аргумент splitOn по умолчанию равен «Id», потому что это обычно первое имя столбца любой таблицы. Я считаю, что splitOn также принимает список имен столбцов с разделителями-запятыми, что может быть удобно, если вы комбинируете более двух таблиц, а разделенные столбцы разные.


Если результаты из запроса/SProc не в определенном порядке (скажем, он вернулся столбцов в порядке FirstName, AccountNumber, LastName), то Щеголеватый не собирается быть в состоянии помочь.

 Смежные вопросы

  • Нет связанных вопросов^_^