如何拆分列的第二个实例
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
对于大多数查询,我正在尝试从 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