LINQ - 基于JOIN命令更改SQL脚本

时间:2018-02-02 00:52:23

标签: c# asp.net entity-framework linq linq-to-entities

这对我来说只是一种奇怪的行为。

LINQ转换我的语句创建奇怪的执行计划。它在我不要求时添加子查询,并且根据我的联接顺序包含或排除此子查询中的联接,这让我感到头疼。在这一点上,根据LINQ to Entities的不可预测性,我不可能优化这个脚本。

SETUP

//define global filter
Expression<Func<Contract_SeqExecution, bool>> globalFilter = r => r.ModifiedByFirstName.Contains("w");

...

//extend global filter
Expression<Func<Contract_SeqExecution, bool>> descendantFilter = x => x.client_id == 1 && x.project_status == true && x.parentId != null;
descendantFilter = descendantFilter.And(globalFilter);

//query
IQueryable<Contract_SeqExecution> geDescendantResults = c.queryGroups(this);

//execute
geDescendantResults.AsExpandable().Where(descendantFilter).Dump();

LINQ QUERY

public IQueryable<Contract_SeqExecution> queryGroups(UserQuery context)
{
        var result = (from ge in context.group_execution
                        join aseq in context.automation_sequences on ge.automation_sequence_id equals aseq.id
                        join modify_u in context.users on aseq.last_modified_by_id equals modify_u.id into modify_uSub
                        from modify_u in modify_uSub.DefaultIfEmpty()
                        join p in context.project on aseq.project_id equals p.id
                        join asstatus in context.automation_sequence_status on ge.run_status_id equals asstatus.id
                        join es in context.execution_schedule on ge.schedule_id equals es.id
                        join exe_u in context.users on ge.executed_by_id equals exe_u.id
                        join create_u in context.users on aseq.created_by_id equals create_u.id
                        select new Contract_SeqExecution
                        {
                            client_id = p.client_id,
                            project_status = p.status,
                            ID = ge.id,
                            Name = aseq.name,
                            ModifiedByFirstName = modify_u.first_name,
                            ModifiedByLastName = modify_u.last_name,
                            FailedInd = asstatus.fail_alert_ind,
                            parentId = ge.parent_group_exec_id,
                            patriarchId = ge.patriarch_id
                        });
        return result;
}

如果我在上面的语句中重新排序连接,我的执行计划会更改,而LINQ-to-entities决定我想要一个子查询....叹息。

严重的是,我所做的只是更改下图中连接的顺序。完全不同的执行计划,这将在以后损害查询的性能。是什么赋予了?我错过了一些明显的东西吗?

enter image description here

enter image description here

是否从实体框架架构中提取信息?是否可能缺少推动这种疯狂行为的FK定义或索引?在这一点上,我只是在黑暗中拍摄。希望这里有人可以对此有所了解。

以下是Contract_SeqExecution类。我目前在LinqPad C#程序中运行这个程序,命中我的DAL dll,linq-to-entities。

public class Contract_SeqExecution
{
    public int ID { get; set; }   
    public string Name { get; set; }
    public string DisplayName { get; set; }
    public int SeqID { get; set; }
    public int CaseGroupInd { get; set; }
    public string CaseGroupText { get; set; }
    public string ExecRatio { get; set; }
    public string ModifiedByFirstName { get; set; }
    public string ModifiedByLastName { get; set; }
    public string Project { get; set; }
    public string Uploaded { get; set; }
    public string UploadRatio { get; set; }
    public bool FailedInd { get; set; }
    public bool HoldInd { get; set; }
    public int? parentId { get; set; }
    public int? patriarchId { get; set; }
    public DateTime? SchedRunTime { get; set; }

    //other fields
    public string Machine {get;set;}
    public int is_accepting_changes {get;set;}
    public string holding_at_name {get;set;}
    public string RunStatus {get;set;}
    public string CaseGroupStatus {get; set;}
    public string TCStatusColor {get; set;}
    public string ExecutedBy {get;set;}
    public string CreatedBy {get;set;}
    public int? ScheduleID {get;set;}
    public bool SeqUploaded {get;set;}
    //end other fields

    public int? parent_group_exec_id { get; set; }
    public int client_id { get; set; }
    public bool project_status { get; set; }

    public IQueryable<Contract_SeqExecution> queryGroups(UserQuery context)
    {
            var result = (from ge in context.group_execution
                            join asstatus in context.automation_sequence_status on ge.run_status_id equals asstatus.id
                            join es in context.execution_schedule on ge.schedule_id equals es.id
                            join exe_u in context.users on ge.executed_by_id equals exe_u.id
                            join aseq in context.automation_sequences on ge.automation_sequence_id equals aseq.id
                            join p in context.project on aseq.project_id equals p.id
                            join create_u in context.users on aseq.created_by_id equals create_u.id
                            join modify_u in context.users on aseq.last_modified_by_id equals modify_u.id into modify_uSub
                            from modify_u in modify_uSub.DefaultIfEmpty()
                            select new Contract_SeqExecution
                            {
                                client_id = p.client_id,
                                project_status = p.status,
                                ID = ge.id,
                                Name = aseq.name,
                                ModifiedByFirstName = modify_u.first_name,
                                ModifiedByLastName = modify_u.last_name,
                                FailedInd = asstatus.fail_alert_ind,
                                parentId = ge.parent_group_exec_id,
                                patriarchId = ge.patriarch_id,
                            });
            return result;
    }
}

更新

所以我接受了安德鲁的建议,并考虑做更多&#34; LINQ&#34;办法。我喜欢在我的实体中包含FK,因为我觉得它是一种更自然的编写SQL的方式,习惯很难。我继续重写我的LINQ表达式,结果现在一致。

示例:

var result = (from ge in context.group_execution
                //join asstatus in context.automation_sequence_status on ge.run_status_id equals asstatus.id
                //join es in context.execution_schedule on ge.schedule_id equals es.id
                //join exe_u in context.users on ge.executed_by_id equals exe_u.id
                //join aseq in context.automation_sequences on ge.automation_sequence_id equals aseq.id
                //join p in context.project on aseq.project_id equals p.id
                //join create_u in context.users on aseq.created_by_id equals create_u.id
                //join modify_u in context.users on aseq.last_modified_by_id equals modify_u.id into modify_uSub
                //from modify_u in modify_uSub.DefaultIfEmpty()
                select new Contract_SeqExecution
                {
                    //client_id = p.client_id,
                    //project_status = p.status,
                    ID = ge.id,
                    Name = ge.automation_sequences.name,
                    ModifiedByFirstName = ge.automation_sequences.modified_by_user.first_name,
                    ModifiedByLastName = ge.automation_sequences.modified_by_user.last_name,
                    //FailedInd = asstatus.fail_alert_ind,
                    parentId = ge.parent_group_exec_id,
                    patriarchId = ge.patriarch_id,
                });
return result;

0 个答案:

没有答案