在dapper中使用一对多关系时出现splitOn错误

Posted

技术标签:

【中文标题】在dapper中使用一对多关系时出现splitOn错误【英文标题】:splitOn Error while using one to many relation in dapper 【发布时间】:2018-05-26 13:04:02 【问题描述】:

我正在尝试使用 dapper 的 Multimapping 功能来返回 MenuCategories 和相关菜单的列表。但我收到以下错误:-

使用多映射 API 时,请确保设置 splitOn 参数,如果 您有除 Id 以外的密钥

这是我的课程:-

VMMenuCategory.cs

public class VMMenuCategory
    
        public int MenuCategoryID  get; set; 
        public string CategoryName  get; set; 
        public System.DateTime CreatedOn  get; set; 
        public DateTime? UpdatedOn  get; set; 


        public List<VMMenu> Menus  get; set; 
    

VMMenus.cs

 public class VMMenu
    
        public int MenuID  get; set; 
        public int MenuCategoryID  get; set; 
        public string ProductName  get; set; 
        public int? CostPrice  get; set; 
        public int? SellingPrice  get; set; 
        public System.DateTime CreatedOn  get; set; 
        public DateTime? UpdatedOn  get; set; 

    

MenuCategoriesRepository.cs

public sealed class MenuCategoryRepository : Connection, IMenuCategoryRepository
    


        List<VMMenuCategory> IMenuCategoryRepository.GetAllMenuCategories()
        
            List<VMMenuCategory> _lstVMMenuCategory = new List<VMMenuCategory>();
            string query = "select * from [dbo].[MenuCategories]";
            using (var connection = GetConnection())
            
                var data = connection.Query<VMMenuCategory, VMMenu, VMMenuCategory>(query, map:(mc,m) =>  mc.Menus =new List<VMMenu>() ;return mc; ,splitOn: "MenuID").ToList();
                return data;
            
            //return _lstVMMenuCategory;
        
    

【问题讨论】:

看起来[dbo].[MenuCategories] 表没有MenuID 列。 @DmitryEgorov,是的,它是一个子表。我试过splitOn: "MenuCategoryID",但我得到了同样的错误。 那么你需要在这个查询中加入两个表。 @DmitryEgorov,所以没有加入就没有办法做到这一点。作为实体框架在 ORM 中工作? 恐怕不行。 Dapper 不知道在哪里可以找到 VMMenu 的数据,除非您在查询中告诉它。 【参考方案1】:

为了使用来自两个表的数据填充两个对象,您必须查询这两个表。在您的情况下,它很可能是内部连接:

public sealed class MenuCategoryRepository : Connection, IMenuCategoryRepository

    List<VMMenuCategory> IMenuCategoryRepository.GetAllMenuCategories()
    
        List<VMMenuCategory> _lstVMMenuCategory = new List<VMMenuCategory>();
        string query = @"
            select mc.*, m.*
            from [dbo].[MenuCategories] mc,
            join [dbo].[Menus] m on mc.MenuCategoryID = m.MenuCategoryID
        ";
        using (var connection = GetConnection())
        
            var data = connection.Query<VMMenuCategory, VMMenu, VMMenuCategory>(
               query,
               map:(mc,m) => 
                   var foundMc = _lstVMMenuCategory
                       .FirstOrDefault(x => x.MenuCategoryID = mc.MenuCategoryID);
                   if (foundMc == null) 
                       foundMc = mc;
                       foundMc.Menus = new List<VMMenu>() ;
                   
                   foundMc.Menus.Add(m);
                   return mc; 
               ,
               splitOn: "MenuID").ToList();
        
        return _lstVMMenuCategory;
    

注意:我猜到了第二个表名,并假设MenuIDMenus 表定义中排在第一位。但是,最好在 select 子句中明确列出所有必需的列。

我还略微修改了映射器函数以避免类别集合中的重复。

【讨论】:

我已为您的答案投了票。感谢您节省了我的时间。你真是太棒了。 我没有得到想要的结果。我需要菜单类别下的菜单。基本上我需要分层数据。但我正在为每个菜单获取菜单类别。但我需要一个具有多个菜单的菜单类别。实际上,sql 查询的结果是相同的。【参考方案2】:

为了填充分层数据,我更改了方法。

下面是代码:

public sealed class MenuCategoryRepository : Connection, IMenuCategoryRepository
    
        List<VMMenuCategory> IMenuCategoryRepository.GetAllMenuCategories()
        
            List<VMMenuCategory> _lstVMMenuCategory = new List<VMMenuCategory>();
            string query = @"
            select mc.*, m.*
            from [dbo].[MenuCategories] mc
            join [dbo].[Menu] m on mc.MenuCategoryID = m.MenuCategoryID";
            using (var connection = GetConnection())
            
                var vmMenuCategoryDictionary = new Dictionary<int, VMMenuCategory>();
                var data = connection.Query<VMMenuCategory, VMMenu, VMMenuCategory>(
                   query,
                   map: (mc, m) =>
                   
                       VMMenuCategory _VMMenuCategory;
                       if(!vmMenuCategoryDictionary.TryGetValue(mc.MenuCategoryID,out _VMMenuCategory))
                       
                           _VMMenuCategory = mc;
                           _VMMenuCategory.Menus = new List<VMMenu>();
                           vmMenuCategoryDictionary.Add(_VMMenuCategory.MenuCategoryID, _VMMenuCategory);

                       
                       _VMMenuCategory.Menus.Add(m);                   
                       return _VMMenuCategory;
                   ,
                   splitOn: "MenuID").Distinct().ToList();
                _lstVMMenuCategory = data;
            
            return _lstVMMenuCategory;
        
    

【讨论】:

以上是关于在dapper中使用一对多关系时出现splitOn错误的主要内容,如果未能解决你的问题,请参考以下文章

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

Dapper 中的多重映射。在 SpiltOn 中接收错误

Dapper Multi-mapping APIs splitOn param Error - 我没有使用 MultiMapping

如何在Dapper.Net中编写一对多查询?

Json序列化,有多对一和多对多关系时出现的问题

三层架构的一点理解以及Dapper一对多查询