Al utilizar las API de mapeo múltiple, asegúrese de configurar el parametro splitOn si tiene claves que no sean Id ..., "splitOn with Multiple relations"

.net asp.net c# dapper orm

Pregunta

Obtengo la siguiente excepción cuando intento ejecutar este método:

Al usar las API de mapeo múltiple, asegúrese de configurar el parametro splitOn si tiene claves que no sean Id ...


public static IEnumerable<FinancePositionList> GetFinancialListsForConsecutiveYears(int year, int periodTypeId, int period)
        {
            IEnumerable<FinancePositionList> resultList;
            using (var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["Finance"].ConnectionString))
            {
                conn.Open();
                StringBuilder query = new StringBuilder();
                query.Append("SELECT b.CompanyId,b.CompanyName,[Year]");
                query.Append(",CreationDate,AccruedExpenses,AdvancePaymentsToContractors");


                query.Append("FROM finance.FinanceList a INNER JOIN finance.Company b ");
                query.Append("ON a.CompanyId = b.CompanyId ");
                query.Append("INNER JOIN finance.ListPeriod c ");
                query.Append("ON c.FinanceListId = a.FinanceListId ");
                query.Append("WHERE Discriminator = " + "'" + "FinancePositionList" + "' ");
                query.Append("AND[Year] IN @years ");
                query.Append("AND c.PeriodTypeId = @PeriodTypeId AND c.Period = @Period ");
                query.Append("ORDER BY b.CompanyId, a.[Year] DESC ");

                resultList = conn.Query<FinancePositionList, Company,ListPeriod, FinancePositionList>(query.ToString(),
                   (a, b,c) =>
                   {
                       a.Company = b;
                       c.FinanceList = a;
                       return a;
                   },
                  new
                  {
                      years = new[] { year, year - 1 },
                      PeriodTypeId = periodTypeId,
                      Period = period
                  },
                    splitOn: "CompanyId,FinanceListId").AsEnumerable();
            }
            return resultList;
        }

enter image description here


EDITAR:

Soluciono el problema ahora cambiando el orden de las columnas de esta manera: ¿Pero me pregunto si hay más mejoras en el código que podría hacer?

 public static IEnumerable<FinancePositionList> GetFinancialListsForConsecutiveYears(int year, int periodTypeId, int period)
        {
            IEnumerable<FinancePositionList> resultList;
            using (var conn = new SqlConnection(ResolveConnectionString()))
            {
                conn.Open();
                StringBuilder query = new StringBuilder();
                query.Append("SELECT CreationDate,AccruedExpenses,AdvancePaymentsToContractors,[Year]");
                query.Append(",b.CompanyId,b.CompanyName,c.FinanceListId ");
                query.Append("FROM finance.FinanceList a INNER JOIN finance.Company b ");
                query.Append("ON a.CompanyId = b.CompanyId ");
                query.Append("INNER JOIN finance.ListPeriod c ");
                query.Append("ON c.FinanceListId = a.FinanceListId ");
                query.Append("WHERE Discriminator = " + "'" + "FinancePositionList" + "' ");
                query.Append("AND [Year] IN @years ");
                query.Append("AND c.PeriodTypeId = @PeriodTypeId AND c.Period = @Period ");
                query.Append("ORDER BY b.CompanyId, a.[Year] DESC ");

                resultList = conn.Query<FinancePositionList, Company, ListPeriod, FinancePositionList>(query.ToString(),
                   (a, b, c) =>
                   {
                       a.Company = b;
                       a.CompanyId = b.CompanyId;
                       a.FinanceListId = c.FinanceListId;
                       return a;
                   },
                  new
                  {
                      years = new[] { year, year - 1 },
                      PeriodTypeId = periodTypeId,
                      Period = period
                  },
                    splitOn: "CompanyId,FinanceListId").AsEnumerable();
            }
            return resultList;
        }

Respuesta aceptada

En su mayoría ha entendido mal el funcionamiento de Multimapping utilizando Dapper . Su consulta arroja las siguientes columnas:

**"CompanyId","CompanyName","Year","CreationDate","AccruedExpenses",
"AdvancePaymentsToContractors"**

Ahora, en el código multimapping , a continuación se muestra la sobrecarga de Query apresurada a la que llama (verificada desde el source code ):

public static IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TReturn>(
this IDbConnection cnn, string sql, Func<TFirst, TSecond, TThird, TReturn> map, 
object param, IDbTransaction transaction, bool buffered, string splitOn, 
int? commandTimeout, CommandType? commandType)

Anteriormente entendí mal la llamada general, pero ahora, como parece, el problema es solo con la asignación de tipos de asignación múltiple utilizando SplitOn , que ya ha corregido, por lo tanto, lo siguiente funcionaría, siempre que las columnas de spliton estén disponibles en el resultado de la consulta

conn.Query<FinancePositionList, Company,ListPeriod, FinancePositionList>(query.ToString(), (a, b,c) =>
                   {
                       a.Company = b;
                       c.FinanceList = a;
                       return a;
                   },
                  new
                 {
                    years = new[] { year, year - 1 },
                    PeriodTypeId = periodTypeId,
                    Period = period
                 }, splitOn: "CompanyId,FinanceListId")

Ahora solo queda aclarar el punto, ya que he publicado en el comentario que está funcionando el parámetro years , que principalmente es una integer array , para la consulta actual que es todo el texto, esto funcionaría bien, pero no para los stored procedures , donde lo haría se espera lo mismo con DataTable , con la misma secuencia y el mismo nombre de las columnas, ya que la colección solo se puede suministrar utilizando los Table Valued Parameters . No preveo más cambios necesarios para el caso de uso actual.

Editar para proporcionar un ejemplo de parámetros anónimos y parámetros dinámicos:

AnonymousParameters

Este tipo anónimo simple en C #, verifique aquí , la idea es que puede suministrar todos los parámetros usando un marcador de posición simple como {max = <value>,min=<value>} o incluso si el nombre coincide con {max,min} , en los dos parámetros de casos son @max y @min , caso no importa, está usando los parámetros AnonymousParameters en su código para los parámetros years, PeriodTypeId, Period , deducirá el tipo y otros detalles internamente y supondría que todos serían ingresados parámetros

{years = new[] { year, year - 1 },PeriodTypeId = periodTypeId,Period = period}

Parámetros dinámicos

Son más parecidos a la clase de parámetros en Ado.Net, lo que le permite agregar un parámetro explícitamente, a continuación están las sobrecargas en el código Dapper, debe proporcionar toda la información como Type, Direction etc. explícitamente (fragmento de código del código fuente apuesto ) :

public partial class DynamicParameters : SqlMapper.IDynamicParameters, SqlMapper.IParameterLookup, SqlMapper.IParameterCallbacks
    {
    public void Add(string name, object value, DbType? dbType, ParameterDirection? direction, int? size)

    public void Add(string name, object value = null, DbType? dbType = null, ParameterDirection? direction = null, int? size = null, byte? precision = null, byte? scale = null)
    }


Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué