Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

WithTempQuery().ToChunAsyncEnumerable()和WithTempQuery.ToListAsync()行为不一致。

Open
#2,288 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
25/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
csharp, sql
Domain
databases

Research direction

The payload shows no FreeSql source files, only a repro: the same WithTempQuery chain run through ToChunkAsyncEnumerable and through ToListAsync, with the generated SQL for the first path. Start by reproducing with a small model using a navigation property inside the temp-query selector, then compare the two SQL outputs. Done means both paths emit the same SQL for the same selector, with no extra join and no missing alias.

Written by the indexing model from the issue text.

Description

问题描述及重现代码:

WithTempQuery()中的select表达式中的实体类用的是一个和表映射的实体类对象。然后在TempQuery中做了过滤筛选,器中过滤条件包含了导航属性下的实体类字段。如果是直接ToListAsync查询返回数据,生成的sql没有任何问题,但是使用ToChunkAsyncEnumerable,生成的sql会多一个连表语句。但是由于已经用TempQuery字段做了别名,所以会抛出没有这个字段。但实际上连这个连表语句都不需要的。对应的实体类以及查询代码如下:

实体类:

[ Table(Name = "case_info", DisableSyncStructure = true)]
	public partial class CaseInfo  {

		/// <summary>
		/// 案件ID
		/// </summary>
		[ Column(Name = "case_id", StringLength = 50, IsPrimary = true, IsNullable = false)]
		public string Id { get; set; } = Guid.NewGuid().ToString().ToUpper();
		
		

		/// <summary>
		/// 发明名称
		/// </summary>
		[ Column(Name = "case_name", StringLength = 500)]
		public string CaseName { get; set; }


		/// <summary>
		/// 承办部门
		/// </summary>
		[ Column(Name = "undertake_dept_id", StringLength = 50)]
		public string UndertakeDeptId { get; set; }

		
		/// <summary>
		/// 卷号
		/// </summary>
		[ Column(Name = "volume", StringLength = 50)]
		public string Volume { get; set; }


       

        /// <summary>
        /// 案件扩展信息
        /// </summary>
        [Navigate(nameof(Id))]
		public virtual CaseExtendInfo? ExtendInfo { get; set; }


       
	}


       [ Table(Name = "case_extend_info", DisableSyncStructure = true)]
public partial class CaseExtendInfo {

    [ Column(Name = "case_id", StringLength = 50, IsPrimary = true, IsNullable = false)]
    public string CaseId { get; set; }

    /// <summary>
    /// 预估风险费
    /// </summary>
    [Column(Name = "estimated_risk_fee")]
    public decimal EstimatedRiskFee { get; set; }

}


[ Table(Name = "sys_user_info", DisableSyncStructure = true)]
	public partial class SysUserInfo {

		[ Column(Name = "user_id", StringLength = 50, IsPrimary = true, IsNullable = false)]
		public string UserId { get; set; }
		/// <summary>
		/// 部门id
		/// </summary>
		[Column(Name = "dept_id", StringLength = 50)]
		public string DeptId { get; set; } = null!;

	}


/// <summary>
    /// 案件任务信息
    /// </summary>
    [Table(Name = "case_proc_info", DisableSyncStructure = true)]
    public class CaseProcInfo : IVersionEntity, ISystemLoggable<CaseProcInfo>
    {

        /// <summary>
        /// 主键ID
        /// </summary>
        [Display(Name = "任务ID", Order = 0)]
        [Hide]
        [Column(Name = "proc_id", StringLength = 50, IsPrimary = true, IsNullable = false)]
        public string ProcId { get; set; } = Guid.NewGuid().ToString().ToUpper();

        /// <summary>
        /// 事项名称ID
        /// </summary>
        [Column(Name = "ctrl_proc_id", StringLength = 200)]
        public string CtrlProcId { get; set; }

        /// <summary>
        /// 事项状态ID
        /// </summary>
        [Column(Name = "proc_status_id", StringLength = 50)]
        public string? ProcStatusId { get; set; }
        /// <summary>
        /// 承办人
        /// </summary>
        [Column(Name = "undertake_user_id", StringLength = 50)]
        public string? UndertakeUserId { get; set; }

        /// <summary>
        /// 任务贡献比
        /// </summary>
        [Column(Name = "project_schedule")]
        public decimal? ProjectSchedule { get; set; }

        
        /// <summary>
        ///  承办人信息
        /// </summary>
        [Navigate(nameof(UndertakeUserId))]
        public virtual SysUserInfo? UndertakeUserInfo { get; set; }

        
    }

/// <summary>
/// 任务进度
/// </summary>
[Table(Name = "case_proc_schedule", DisableSyncStructure = true)]
public partial class CaseProcSchedule
{

    /// <summary>
    /// 主键
    /// </summary>
    [Column(Name = "schedule_id", StringLength = 50, IsPrimary = true, IsNullable = false)]
    public string ScheduleId { get; set; } = null!;

    /// <summary>
    /// 创建时间
    /// </summary>
    [Column(Name = "create_time")]
    public DateTime CreateTime { get; set; }

    /// <summary>
    /// 创建用户id
    /// </summary>
    [Column(Name = "create_user_id", StringLength = 50, IsNullable = false)]
    public string CreateUserId { get; set; } = null!;

    /// <summary>
    /// 年-月
    /// </summary>
    [Column(Name = "filling_time")]
    public DateTime? FillingTime { get; set; }

    /// <summary>
    /// 任务id
    /// </summary>
    [Column(Name = "proc_id", StringLength = 50, IsNullable = false)]
    public string ProcId { get; set; } = null!;

    /// <summary>
    /// 进度
    /// </summary>
    [Column(Name = "progress")]
    public decimal? Progress { get; set; }

    /// <summary>
    /// 耗时天数
    /// </summary>
    [Column(Name = "cost_days", DbType = "decimal(5,1)")]
    public decimal CostDays { get; set; }

    /// <summary>
    /// 进度详情
    /// </summary>
    [Column(Name = "schedule_detail", StringLength = 1000, IsNullable = false)]
    public string ScheduleDetail { get; set; } = string.Empty;

    /// <summary>
    /// 更新时间
    /// </summary>
    [Column(Name = "update_time")]
    public DateTime? UpdateTime { get; set; }

    /// <summary>
    /// 更新用户id
    /// </summary>
    [Column(Name = "update_user_id", StringLength = 50)]
    public string? UpdateUserId { get; set; }

    /// <summary>
    /// 关联的任务信息
    /// </summary>
    [Navigate(nameof(ProcId))]
    public virtual CaseProcInfo? ProcInfo { get; set; }

}

查询条件构造

var query = freeSql.Select<CaseProcSchedule>().WithLock()
            .InnerJoin(s => s.ProcId == s.ProcInfo!.ProcId)
            .InnerJoin(s => s.ProcInfo!.CaseId == s.ProcInfo!.CaseInfo.Id)
            .Where(s => s.ProcInfo!.CaseInfo.CaseTypeId == "X")
            .Where(s => request.FillingTimes.Contains(s.FillingTime!.Value))
            .Where(s => request.UndertakerIds.Contains(s.ProcInfo!.UndertakeUserId!))
            .WithTempQuery(s => new CaseProcSchedule
                {
                    ScheduleId = s.ScheduleId,
                    CreateTime = s.CreateTime,
                    FillingTime = s.FillingTime,
                    ProcId = s.ProcId,
                    Progress = s.Progress,
                    CostDays = s.CostDays,
                    ScheduleDetail = s.ScheduleDetail,
                    ProcInfo = new CaseProcInfo()
                    {
                        ProcId = s.ProcInfo!.ProcId,
                        CtrlProcId = s.ProcInfo!.CtrlProcId,
                        ProcStatusId = s.ProcInfo!.ProcStatusId,
                        ProjectSchedule = s.ProcInfo!.ProjectSchedule,
                        UndertakeUserId = s.ProcInfo!.UndertakeUserId,
                        UndertakeUserInfo = new SysUserInfo()
                        {
                            UserId = s.ProcInfo!.UndertakeUserInfo!.UserId,
                            DeptId = s.ProcInfo!.UndertakeUserInfo!.DeptId,
                        },
                        CaseInfo = new CaseInfo()
                        {
                            Id = s.ProcInfo!.CaseInfo.Id,
                            CaseName = s.ProcInfo!.CaseInfo.CaseName,
                            Volume = s.ProcInfo!.CaseInfo.Volume,
                            UndertakeDeptId = s.ProcInfo!.CaseInfo.UndertakeDeptId,
                            ExtendInfo = new CaseExtendInfo()
                            {
                                CaseId = s.ProcInfo!.CaseInfo.ExtendInfo!.CaseId,
                                EstimatedRiskFee = s.ProcInfo!.CaseInfo.ExtendInfo.EstimatedRiskFee
                            }
                        }
                    }
                }).Where(s => request.UndertakeUserIds.Contains(s.ProcInfo!.UndertakeUserId))
               

ToChunkAsyncEnumerable

await foreach (var productivityInfos in query.ToChunkAsyncEnumerable(s => new ProductivityInfo
                       {
                           CreateTime = s.CreateTime,
                           ScheduleId = s.ScheduleId,
                           ProcId = s.ProcId,
                           CaseId = s.ProcInfo!.CaseId,
                           ProgressMonth = $"{s.FillingTime!.Value.Year}年{s.FillingTime.Value.Month}月",
                           ProgressValue = s.Progress ?? 0,
                           ScheduleDetail = s.ScheduleDetail,
                           ContributionRatio = s.ProcInfo!.ProjectSchedule,
                           Volume = s.ProcInfo!.CaseInfo.Volume,
                           CaseName = s.ProcInfo!.CaseInfo.CaseName,
                           UndertakeDepartment = s.ProcInfo!.CaseInfo.UndertakeDeptId,
                           ProcName = s.ProcInfo!.CtrlProcId,
                           ProcStatus = s.ProcInfo!.ProcStatusId ?? string.Empty,
                           Undertaker = s.ProcInfo!.UndertakeUserId ?? string.Empty,
                           ProgressCostDays = s.CostDays,
                           EstimatedRiskFee = s.ProcInfo!.CaseInfo.ExtendInfo!.EstimatedRiskFee
                       }, 10).WithCancellation(cancellationToken))
SELECT a.[CreateTime] as1, a.[ScheduleId] as2, a.[ProcId2] as3, a__ProcInfo.[case_id] as4, N''+isnull(cast(datepart(year, a.[FillingTime]) as varchar), '')+N'年'+isnull(cast(datepart(month, a.[FillingTime]) as varchar), '')+N'月' as5, isnull(a.[Progress], 0) as6, a.[ScheduleDetail] as7, a.[ProjectSchedule] as8, a.[Volume] as9, a.[CaseName] as10, a.[UndertakeDeptId] as11, a.[CtrlProcId] as12, isnull(a.[ProcStatusId], '') as13, isnull(a.[UndertakeUserId], '') as14, a.[CostDays] as15, a.[EstimatedRiskFee] as16
FROM (
         SELECT a.[schedule_id] [ScheduleId], a.[create_time] [CreateTime], a.[filling_time] [FillingTime], a.[proc_id] [ProcId], a.[progress], a.[cost_days] [CostDays], a.[schedule_detail] [ScheduleDetail], a__ProcInfo.[proc_id] [ProcId2], a__ProcInfo.[ctrl_proc_id] [CtrlProcId], a__ProcInfo.[proc_status_id] [ProcStatusId], a__ProcInfo.[project_schedule] [ProjectSchedule], a__ProcInfo.[undertake_user_id] [UndertakeUserId], a__ProcInfo__UndertakeUserInfo.[user_id] [UserId], a__ProcInfo__UndertakeUserInfo.[dept_id] [DeptId], a__ProcInfo__CaseInfo.[case_id] [Id], a__ProcInfo__CaseInfo.[case_name] [CaseName], a__ProcInfo__CaseInfo.[volume], a__ProcInfo__CaseInfo.[undertake_dept_id] [UndertakeDeptId], a__ProcInfo__CaseInfo__ExtendInfo.[case_id] [CaseId], a__ProcInfo__CaseInfo__ExtendInfo.[estimated_risk_fee] [EstimatedRiskFee]
         FROM [case_proc_schedule] a With(NoLock)
                  INNER JOIN [case_proc_info] a__ProcInfo With(NoLock) ON a.[proc_id] = a__ProcInfo.[proc_id]
                  INNER JOIN [case_info] a__ProcInfo__CaseInfo With(NoLock) ON a__ProcInfo.[case_id] = a__ProcInfo__CaseInfo.[case_id]
                  LEFT JOIN [sys_user_info] a__ProcInfo__UndertakeUserInfo With(NoLock) ON a__ProcInfo__UndertakeUserInfo.[user_id] = a__ProcInfo.[undertake_user_id]
                  LEFT JOIN [case_extend_info] a__ProcInfo__CaseInfo__ExtendInfo With(NoLock) ON a__ProcInfo__CaseInfo__ExtendInfo.[case_id] = a__ProcInfo__CaseInfo.[case_id]
         WHERE (a__ProcInfo__CaseInfo.[case_type_id] = N'X') AND (((a.[filling_time]) in ('2026-10-01 00:00:00.000'))) AND (((a__ProcInfo.[undertake_user_id]) in (N'06e41cf0-88db-4c05-95a0-3c8b6afcb238'))) ) a
         LEFT JOIN [case_proc_info] a__ProcInfo ON a__ProcInfo.[proc_id] = a.[proc_id]
WHERE (((a.[UndertakeUserId]) in (N'06e41cf0-88db-4c05-95a0-3c8b6afcb238')))

toListAync查询

数据库版本
var list = query.ToListAsync(s => new ProductivityInfo
        {
            CreateTime = s.CreateTime,
            ScheduleId = s.ScheduleId,
            ProcId = s.ProcId,
            CaseId = s.ProcInfo!.CaseInfo.Id,
            ProgressMonth = $"{s.FillingTime!.Value.Year}年{s.FillingTime.Value.Month}月",
            ProgressValue = s.Progress ?? 0,
            ScheduleDetail = s.ScheduleDetail,
            ContributionRatio = s.ProcInfo!.ProjectSchedule,
            Volume = s.ProcInfo!.CaseInfo.Volume,
            CaseName = s.ProcInfo!.CaseInfo.CaseName,
            UndertakeDepartment = s.ProcInfo!.CaseInfo.UndertakeDeptId,
            ProcName = s.ProcInfo!.CtrlProcId,
            ProcStatus = s.ProcInfo!.ProcStatusId ?? string.Empty,
            Undertaker = s.ProcInfo!.UndertakeUserId ?? string.Empty,
            // UndertakerDepartment = s.ProcInfo!.UndertakeUserInfo!.DeptId,
            ProgressCostDays = s.CostDays,
            EstimatedRiskFee = s.ProcInfo!.CaseInfo.ExtendInfo!.EstimatedRiskFee
        }, cancellationToken);

sql语句

SELECT a.[CreateTime] as1, a.[ScheduleId] as2, a.[ProcId] as3, a.[Id] as4, N''+isnull(cast(datepart(year, a.[FillingTime]) as varchar), '')+N'年'+isnull(cast(datepart(month, a.[FillingTime]) as varchar), '')+N'月' as5, isnull(a.[Progress], 0) as6, a.[ScheduleDetail] as7, a.[ProjectSchedule] as8, a.[Volume] as9, a.[CaseName] as10, a.[UndertakeDeptId] as11, a.[CtrlProcId] as12, isnull(a.[ProcStatusId], '') as13, isnull(a.[UndertakeUserId], '') as14, a.[CostDays] as15, a.[EstimatedRiskFee] as16
FROM (
         SELECT a.[schedule_id] [ScheduleId], a.[create_time] [CreateTime], a.[filling_time] [FillingTime], a.[proc_id] [ProcId], a.[progress], a.[cost_days] [CostDays], a.[schedule_detail] [ScheduleDetail], a__ProcInfo.[proc_id] [ProcId2], a__ProcInfo.[ctrl_proc_id] [CtrlProcId], a__ProcInfo.[proc_status_id] [ProcStatusId], a__ProcInfo.[project_schedule] [ProjectSchedule], a__ProcInfo.[undertake_user_id] [UndertakeUserId], a__ProcInfo__UndertakeUserInfo.[user_id] [UserId], a__ProcInfo__UndertakeUserInfo.[dept_id] [DeptId], a__ProcInfo__CaseInfo.[case_id] [Id], a__ProcInfo__CaseInfo.[case_name] [CaseName], a__ProcInfo__CaseInfo.[volume], a__ProcInfo__CaseInfo.[undertake_dept_id] [UndertakeDeptId], a__ProcInfo__CaseInfo__ExtendInfo.[case_id] [CaseId], a__ProcInfo__CaseInfo__ExtendInfo.[estimated_risk_fee] [EstimatedRiskFee]
         FROM [case_proc_schedule] a With(NoLock)
                  INNER JOIN [case_proc_info] a__ProcInfo With(NoLock) ON a.[proc_id] = a__ProcInfo.[proc_id]
                  INNER JOIN [case_info] a__ProcInfo__CaseInfo With(NoLock) ON a__ProcInfo.[case_id] = a__ProcInfo__CaseInfo.[case_id]
                  LEFT JOIN [sys_user_info] a__ProcInfo__UndertakeUserInfo With(NoLock) ON a__ProcInfo__UndertakeUserInfo.[user_id] = a__ProcInfo.[undertake_user_id]
                  LEFT JOIN [case_extend_info] a__ProcInfo__CaseInfo__ExtendInfo With(NoLock) ON a__ProcInfo__CaseInfo__ExtendInfo.[case_id] = a__ProcInfo__CaseInfo.[case_id]
         WHERE (a__ProcInfo__CaseInfo.[case_type_id] = N'X') AND (((a.[filling_time]) in ('2026-10-01 00:00:00.000'))) AND (((a__ProcInfo__UndertakeUserInfo.[dept_id]) in (N'7e3d4e4f-1308-4650-a07b-237348c1de78',N'19acbfb0-8cbf-43f2-b936-07a93add2c55'))) AND (((a__ProcInfo.[undertake_user_id]) in (N'06e41cf0-88db-4c05-95a0-3c8b6afcb238'))) ) a
WHERE (((a.[UndertakeUserId]) in (N'ad0209f1-a52e-4d30-b5dc-3f81241ec9fb')))

ToChunkAsyncEnumerable多了个 LEFT JOIN [case_proc_info] a__ProcInfo ON a__ProcInfo.[proc_id] = a.[proc_id]

感觉是因为最外层多了一个导航属性过滤条件的关系。但是ToListAsync可以适配,ToChunkAsyncEnumerable没有。

安装的Nuget包
Image
.net framework/. net core? 及具体版本

.net 10

Dominant language
C#
Stars
4.4k
Forks
911
Avg merge
12h 47m
Merged PRs (30d)
2

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from dotnetcore/FreeSql

All issues in dotnetcore/FreeSql

Similar issues

More C# issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.