如何拆分列的第二个实例

How do I split on the second instance of a column

对于大多数查询,我正在尝试从 EntityFramework Core 转换为 Dapper。我有一个 sql table (树结构)定义为:

[Table("bma_ec_categories")]
public class Category
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    [Column("category_id")]
    public int CategoryId { get; set; }

    [Column("parent_category_id")]
    public int ParentId { get; set; }

    [Required]
    [Column("category_name")]
    [StringLength(50)]
    public string Name { get; set; }

    public ICollection<Category> Children { get; set; }

    [Column("title")] 
    [StringLength(150)] 
    public string Title { get; set; }

    [Column("description")]
    [StringLength(250)]
    public string Description { get; set; }
    
    [Column("keywords")]
    [StringLength(250)]
    public string Keywords { get; set; }

    [Column("page_content", TypeName = "text")]
    public string PageContent { get; set; }

    [Column("banner_group_id")] 
    public int? BannerGroupId { get; set; }
    
    [Column("inactive")] 
    public bool? Inactive { get; set; }
    
    [Column("issitecategory")] 
    public bool Issitecategory { get; set; }
    
    [Column("sort_order")] 
    public int? SortOrder { get; set; }
}

这是一个tree。我还有一个 dto 定义为:

public class CategoryDto
{
    [Key]
    public int CategoryId { get; set; }

    public int ParentId { get; set; }

    public string Name { get; set; }

    public string Title { get; set; }

    public string Description { get; set; }

    public string Keywords { get; set; }

    public string PageContent { get; set; }

    public int? BannerGroupId { get; set; }

    public bool? Inactive { get; set; }

    public bool Issitecategory { get; set; }

    public int? SortOrder { get; set; }

    public ICollection<CategoryDto> Children { get; set; }
}

我的 Item Service 有我从 EF Core 复制的大部分 Dapper 查询:

    public IEnumerable<CategoryDto> GetCategoriesWithDapperUnbuffered()
    {
        var plainResult =  _dapper.GetCategoriesUnbuffered();

        var categoryDtos = plainResult.ToList();

        var lookup = categoryDtos.Where(x => x.ParentId != 0).ToLookup(x => x.ParentId);

        foreach (var c in categoryDtos)
        {
            if (lookup.Contains(c.CategoryId))
            {
                c.Children = lookup[c.CategoryId]
                    .OrderBy(x => x.SortOrder)
                    .ThenBy(x => x.Name)
                    .ToList();
            }
        }

        var dto = categoryDtos
            .Where(x => x.ParentId == 0)
            .OrderBy(x => x.SortOrder)
            .ThenBy(x => x.Name)
            .ToList();

        return dto;
    }

... 其中 GetCategoriesUnbuffered 是:

    public IEnumerable<CategoryDto> GetCategoriesUnbuffered()
    {
        string sql = "SELECT * FROM [dbo].[bma_ec_categories]";

        using (DbConnection db = _connectionFactory.CreateConnection())
        {
            var categories = db.Query<CategoryDto>(sql, buffered: false).ToList();

            return categories;
        }
    }

我还有一个可以展示的 Dapper Fluent 映射。此查询确实有效。但我正在尝试通过在原始查询中使用 Dapper 的多映射功能来进一步优化。这是我目前所拥有的:

    public IEnumerable<CategoryDto> GetCategoriesMultiMapping()
    {
        string sql = "SELECT * FROM [dbo].[bma_ec_categories] AS [A] INNER JOIN [dbo].[bma_ec_categories] AS [B] ON [A].[category_id] = [B].[parent_category_id];";

        using (DbConnection db = _connectionFactory.CreateConnection())
        {
            var categoryDictionary = new Dictionary<int, CategoryDto>();

            var list = db.Query<CategoryDto, CategoryDto, CategoryDto>(
                    sql,
                    (category, children) =>
                    {
                        if (!categoryDictionary.TryGetValue(category.ParentId, out var categoryEntry))
                        {
                            categoryEntry = category;
                            categoryEntry.Children = new List<CategoryDto>();
                            categoryDictionary.Add(categoryEntry.ParentId, categoryEntry);
                        }

                        categoryEntry.Children.Add(children);
                        return categoryEntry;
                    },
                    splitOn: "category_id,category_id", buffered: false)
                .Distinct()
                .ToList();

            return list;
        }
    }

此 returns 第一个类别,所有其他类别都是其子类别。我 运行 在尝试 splitOn category_id 的第二个实例时遇到了麻烦。我尝试改编来自 Dapper Example - Query Multi-Mapping (One to Many) 的一对多示例。任何帮助将不胜感激。

经过大量搜索,我得出结论,这不是 Multi-Mapper 的本意。但是,我确实在 SO 上找到了这个 ,它解决了我的实际问题。

如果有人想知道这里是我的基准测试结果:

Method Mean Error StdDev StdErr Min Max Q1 Q3 Median Op/s Ratio RatioSD Rank Gen 0 Gen 1 Allocated
'EF Core (async)' 96.87 ms 3.920 ms 11.309 ms 1.154 ms 77.79 ms 126.71 ms 87.62 ms 105.04 ms 95.68 ms 10.32 1.00 0.00 4 - - 979 KB
'EF Core (compiled)' 83.69 ms 1.674 ms 4.910 ms 0.494 ms 73.57 ms 96.66 ms 79.87 ms 86.79 ms 83.52 ms 11.95 0.88 0.11 3 142.8571 - 1,297 KB
'Dapper (async, buffered)' 77.34 ms 1.646 ms 4.828 ms 0.485 ms 65.97 ms 88.00 ms 74.04 ms 80.87 ms 76.98 ms 12.93 0.81 0.12 2 166.6667 - 686 KB
'Dapper (unbuffered)' 66.64 ms 1.322 ms 3.551 ms 0.387 ms 57.91 ms 74.21 ms 64.25 ms 68.98 ms 66.69 ms 15.01 0.70 0.09 1 125.0000 - 593 KB
'Dapper Test (unbuffered)' 66.16 ms 1.322 ms 2.902 ms 0.381 ms 60.57 ms 72.30 ms 63.87 ms 67.97 ms 65.93 ms 15.11 0.67 0.07 1 285.7143 142.8571 1,746 KB
  • Dapper Test 基于我链接到的 SO 答案

如果我真的理解你想把这个 table 作为一棵树来阅读,一种方法是在 SQL 服务器 上使用 递归查询,我就是这样做的.

我在相同情况下使用了存储过程,您可以在 SQL 服务器上使用 sp 或函数,运行 命令 运行 您的 sp.

我为您创建了一个简单的示例;

 DECLARE @CatTree TABLE(category_id int,parent_category_id int,category_name varchar(50) )

 INSERT INTO @CatTree (category_id,parent_category_id,category_name) 
 VALUES (1,null,'shoes'),(2,1,'outdoor shoes'),(3,1,'winter shoes'),(4,3,'water proof shoes'),(5,3,'snow shoes')




 ;WITH TopCat AS (
                SELECT 
                    CAST(category_id AS VARCHAR(MAX))  ID_Path,
                    parent_category_id,
                    category_id,
                    category_name
                
                FROM @CatTree where parent_category_id is null

            UNION ALL

             SELECT  
                r.ID_Path + ' > ' + CAST(t.category_id AS VARCHAR(MAX)),
                t.parent_category_id,
                t.category_id,
                t.category_name
            
            FROM @CatTree t 
            INNER JOIN TopCat r ON  t.parent_category_id = r.category_id
            ) 
            
  select * from TopCat

第二次求助;如果你想在你的后端创建你的树 self referanced tables 是你的关键。你必须添加一个关系到你的模型,指向它自己然后流利 api 或 migraiton 两者都是有用的

public class Category: BaseEntity
{
    public Guid Id{ get; set; }

    public string Name { get; set; }

    public Guid? TopCategoryId{ get; set; }

    public virtual ICollection<Category> TopCat{ get; set; }
}

这可能是错误的我没试过,我只是写在心里。那么你必须将你的关系添加到你的数据注释或流利的api

builder.HasMany(pt => pt.Category).WithOne(p => p.TopCat)

Entity Framework Core self referencing table