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

Posted

技术标签:

【中文标题】Dapper 中的多重映射。在 SpiltOn 中接收错误【英文标题】:Multi Mapping in Dapper. Receiving the error in SpiltOn 【发布时间】:2016-02-25 07:28:11 【问题描述】:

*你能解释一下multimap中的Split on功能吗*

我正在尝试使用 Dapper ORM 从数据库中获取数据。我收到以下错误 System.ArgumentException : 使用多映射 API 时,如果您的键不是 Id,请确保设置 splitOn 参数 参数名称:splitOn

 public abstract class Domain
    
       public Guid Id  get; set; 
    


public abstract class ItemBase : Domain
  
     private IList<Image> images = new List<Image>();
     public Guid? ParentId  get; set; 
     public string Name  get; set; 
     public IList<Image> Images  get  return images;  
  

 public class Meal : ItemBase
   

   

public class Item : ItemBase
  
     private IList<Meal> meals = new List<Meal>();
     public IList<Meal> Meals  get  return meals;  ;
  


public class Image : Domain
  
      public byte Img  get; set; 
       public string Description  get; set; 
   



 public  class MealImageLink : Domain
 
     public Guid ItemId  get; set; 
     public Guid ImageId  get; set; 
 

/* 从表中获取数据的搜索函数 */

private List<Meal> SearchMeals(Guid id)
 
   var query = @"SELECT meal.[Name],meal.[Description],meal.

   [Price],mealImage.[Image] as Img    
                                  FROM      [MealItems] as meal  
                                  LEFT JOIN   [MealImageLink] mealImageLink 

  on meal.Id= mealImageLink.MealItemId
                                  LEFT JOIN   [Images] mealImage on  

   mealImageLink.ImageId=mealImage.Id
                                  WHERE  meal.[ParentId]=@Id";

List<Meal> meals = ( _connection.Query<Meal, MealImageLink, Image, Meal>
                                       (query, (meal, mealLink, mealImage) =>
                                       
                                           meal.Images.Add(mealImage);
                                           return meal;
                                       , new  @Id = id )).ToList();
return meals;

【问题讨论】:

【参考方案1】:

多地图功能更适用于以下场景:

select foo.Id, foo.whatever, ...,
       bar.Id, bar.something, ...,
       blap.Id, blap.yada, ...
from foo ...
inner join bar ...
left outer join blap ...

或者更懒惰但并不少见:

select foo.*, bar.*, blap.*
from ...
inner join bar ...
left outer join blap ...

但是在这两种情况下,有一种清晰明了的方法可以将水平范围划分为多个分区;基本上,每当您看到名为Id 的列时,它就是下一个块。名称Id 可配置为方便起见,并且可以是列的分隔列表,用于每个表具有不同主键名称的情况(因此User 可能有UserId 等)。

您的情况似乎与此完全不同。看起来您目前只选择了 4 列,没有特别的方式将它们分开。我建议在这种情况下,通过不同的 API 更容易填充您的模型 - 特别是 dynamic API:

var meals = new List<Meal>();
foreach(var row in _connection.Query(sql, new  @Id = id ))

    string name = row.Name, description = row.Description;
    decimal price = row.Price;
    // etc

    Meal meal = // TODO: build a new Meal object from those pieces
    meals.Add(meal);

只需不指定任何&lt;...&gt; 即可访问dynamic API。完成后,按名称访问列,它们的类型隐含它们被分配的内容 - 因此类似于:

decimal price = row.Price;

注意:如果你想使用“内联”的row数据,那么只需尽快,即

// bad: forces everything to use dynamic for too long
new Meal(row.Name, row.Description, row.Price);

// good: types are nailed down immediately
new Meal((string)row.Name, (string)row.Description, (decimal)row.Price);

这有帮助吗?

Tl;dr:我只是认为多重映射与您的查询无关。


编辑:这是我对您打算做什么的最佳猜测 - 它根本不适合多地图:

var meals = new List<Meal>();
foreach (var row in _connection.Query(query, new  @Id = id )) 
    meals.Add(new Meal 
        Name = (string)row.Name,
        Images = 
            new Image 
                Description = (string)row.Description,
                Img = (byte)row.Img
            
        
    );

return meals;

【讨论】:

你能详细解释一下代码下面的动态API ` var foods = new List(); foreach(var row in _connection.Query(sql, new @Id = id )) string name = row.Name, description = row.Description;小数价格 = row.Price; // etc Meal meal = // TODO: 从这些碎片中构建一个新的 Meal 对象 ` 根据对spliton函数的理解,我将代码重新整理为List&lt;Meal&gt; meals = ( _connection.Query&lt;Meal, MealImageLink, Image, Meal&gt; (query, (meal, mealLink, mealImage) =&gt; meal.Images.Add(mealImage); return meal; , new @Id = id ,splitOn: "Name")).ToList();,我也收到同样的错误跨度> “我已将代码重新排列为...” - 确实;您告诉它按名为Name 的列拆分水平分区。唯一称为Name 的列发生在第一列。绝对无法获取任何其他分区的任何数据,......所以......消息正确地识别出一些非常错误的东西。 @chaaru "你能详细解释一下吗...";你有 4 列,可以根据我显示的代码提取。一旦你有了这 4 个值,就可以构造一个 Meal(你确实选择了这 4 个值,等等)。我不确定你想让我在那里添加什么...... :"你能详细解释一下吗。"我仍然怀疑我必须在 foreach(var row in _connection.Query(sql, new @Id = id )) 这个或其他任何地方编写执行命令。请给出完整的代码。我是这个 Dapper 和 C# 的新手

以上是关于Dapper 中的多重映射。在 SpiltOn 中接收错误的主要内容,如果未能解决你的问题,请参考以下文章

Dapper 多重映射 - 集合为空

将 Dapper 查询映射到对象集合(它本身有几个集合)

嵌套多映射 Dapper 分页查询中的重复字段名称问题

.NET Dapper - 映射计算属性

dapper可以商用吗

dapper 在 classmapper 中一对一映射