使用多映射 API 时,如果您的键不是 Id“、”splitOn 和多个关系,请确保设置 splitOn 参数

Posted

技术标签:

【中文标题】使用多映射 API 时,如果您的键不是 Id“、”splitOn 和多个关系,请确保设置 splitOn 参数【英文标题】:When using the multi-mapping APIs ensure you set the splitOn param if you have keys other than Id“, ”splitOn with Multiple relations 【发布时间】:2016-10-27 05:20:15 【问题描述】:

当我尝试执行此方法时出现以下异常:

使用多映射 API 时,请确保设置 splitOn 参数,如果 您有除 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;
        


编辑:

我现在通过更改列的顺序来解决问题,如下所示: 但我想知道我是否可以对代码进行更多增强?

 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;
        

【问题讨论】:

【参考方案1】:

您大多误解了使用DapperMultimapping 的工作原理,您的查询产生以下列:

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

现在在multimapping 代码中,以下是您正在调用的精巧Query 重载(从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)

之前我误解了整体调用,但现在看来,问题仅在于使用 SplitOn 的多映射类型映射,您已经更正了,因此,如果正确,以下将起作用查询结果中有spliton

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

现在只有一点需要澄清,因为我在评论中发布的是 years 参数,它主要是 integer array,对于当前查询是所有文本,这可以正常工作,但不适用于stored procedures,其中使用 DataTable 时期望相同​​,只有使用 Table Valued Parameters 才能提供与集合相同的列序列和名称。我预计当前用例不需要任何更改。

编辑以提供匿名参数和动态参数的示例:

匿名参数

C# 中这个简单的匿名类型,检查here,想法是您可以使用简单的占位符(如max = &lt;value&gt;,min=&lt;value&gt;)提供所有参数,或者即使名称匹配max,min,在这两种情况下参数都是@max@min ,大小写无关紧要,您在代码中使用 AnonymousParameters 作为参数 years, PeriodTypeId, Period,它会在内部推断类型和其他详细信息,并假定所有参数都是输入参数

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

动态参数

它们更像是 Ado.Net 中的 Parameter 类,它让您显式添加参数,以下是 Dapper 代码中的重载,您必须显式提供所有信息,如 Type, Direction 等(代码 sn-p来自dapper源代码):

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)
    

【讨论】:

非常感谢,是的,这是我第一次根据建议使用Dapper。如果我使用first 一个如何传递我的参数,我在这里有一个问题。我在这里要做的就是执行一个查询,该查询有多个允许传递参数的连接,所以我做到了。 参数很简单,可以使用匿名类型或动态参数来完成,我更喜欢匿名类型,尽管它们仅限于输入参数,查看示例@github.com/StackExchange/dapper-dot-net 或下载源代码,有了解用法的好测试用例 请您重写我的查询以澄清这个想法 当前您收到编译错误,因为没有查询重载会接受它,它正在搜索 SplitOn 并且您正在传递匿名类型。现在我明白了匿名类型是参数,但你提供的参数不正确,让我重写 抱歉回复晚了,请检查我的编辑以了解差异,直接给我发邮件了解更多详细信息,希望在一定程度上有助于澄清。

以上是关于使用多映射 API 时,如果您的键不是 Id“、”splitOn 和多个关系,请确保设置 splitOn 参数的主要内容,如果未能解决你的问题,请参考以下文章

Dapper - 多映射 API 确保您设置 splitOn

使用 Restkit 0.20 映射此类与键的键值编码不兼容

TypeScript 中是不是有一种编译时方法来声明一个 keyof 类型,只有映射到特定类型的键? [复制]

如何在没有 ID 的 React 中映射数组?

JAVA基础学习-集合三-MapHashMap,TreeMap与常用API

Map集合