I have a class User with a nested class Bank.
class User{
int Id;
string username;
Bank bank;
}
Class Bank{
int id;
string name;
}
I need to create an Insert function for User. Is there a way in Dapperto execute a query and binding the parameters from a nested a object ?
2 Answers 2
You can write a custom mapper for Dapper using DapperExtensions:
public sealed class UserMapper : ClassMapper<User>
{
public UserMapper()
{
Map(x => x.bank.id).Column("BankId");
Map(x => x.bank.name).Column("BankName");
AutoMap();
}
}
https://github.com/tmsmith/Dapper-Extensions/wiki/Customized-mapping-for-a-class
Make sure you register the assembly containing the mapper:
DapperExtensions.SetMappingAssemblies(new[] { typeof(UserMapper).Assembly });
1 Comment
Must declare the scalar variable "@BankId". How do you actually use that nested class in the query after you map it?For such a scenario where not just a User object but a List<User> might also need a db insertion, you can consider using table valued parameters. For your question it would be:
Use
IEnumerable<User>andIEnumerable<Bank>, even if it is just one objectMake the
TVPwith appropriate schema and same order ofcolumnsas inIEnumerable collectionfor the stored procedure, else it will lead to errorYou can use
dynamic parametersto bind the parameters, where forTVP,IEnumerablecan be supplied using extension methodAsTableValuedParametersin case you are usinganonymous typeparameters notdynamic parameters, then use theObjectReaderfromFastMemberin Nuget to convertIEnuemrable<T>toDatatable, which is mandatory for TVP. Even custom code can be used forIEnuemrable<T>toDatatableconversion, in case few columns need to be omitted, following is the code snippet:
public static DataTable CreateTable<TDataTable>(this IEnumerable<TDataTable> collection)
{
// Fetch the type of List contained in the ParamValue
var tableType = typeof(TDataTable);
// Create DataTable which will contain data from List<T>
var dataTable = new DataTable();
// Fetch the Type fields count
var columnCount = tableType.GetProperties().Count();
var columnNameMappingDictionary = new Dictionary<string, string>();
// Create DataTable Columns using table type field name and their types
// Traversing through Column Collection
for (var counter = 0; counter < columnCount; counter++)
{
var propertyInfo = tableType.GetProperties()[counter];
var columnName = propertyInfo.Name;
columnNameMappingDictionary.Add(propertyInfo.Name,
propertyInfo.Name);
// Fetch the current type of a property and check whether its nullable type before adding a column
var currentType = tableType.GetProperties()[counter].PropertyType;
dataTable.Columns.Add(columnName, Nullable.GetUnderlyingType(currentType) ?? currentType);
}
// Return parameter with null value
if (collection == null)
return dataTable;
// Traverse through number of entries / rows in the List
foreach (var item in collection)
{
// Create a new DataRow
var dataRow = dataTable.NewRow();
foreach (var columnName in columnNameMappingDictionary.Select(propertyinfo => propertyinfo.Value))
{
dataRow[columnName] = item.GetType().GetProperty(columnName).GetValue(item) ?? DBNull.Value;
}
// Add Row to Table
dataTable.Rows.Add(dataRow);
}
return (dataTable);
}
new { UserId = u.Id, UserName = u.username, BankId = u.bank.id, BankName = u.bank.name }