Возвращается метод LINQ Any () - PullRequest
0 голосов
/ 30 мая 2018

У меня есть типичное приложение Drill Down.

Вот иерархия моего приложения.

Аудит
имеет много
Выводов

public class Audit
{
    private string _auditAcnCd;
    private string _title;
    private string _summary;

    [Key]
    [Column("audit_id")]
    public int AuditID { get; set; }

    [Required(ErrorMessage = "ACN Required")]
    [Display(Name="ACN:")]
    [Column("audit_acn_cd")]
    public string AuditAcnCd
    {
        get
        {
            return _auditAcnCd;
        }
        set
        {
            _auditAcnCd = value?.Trim();
        }
    }

    [Required(ErrorMessage = "Title Required")]
    [Display(Name = "Title:")]
    [Column("audit_report_title_tx")]
    public string Title
    {
        get
        {
            return _title;
        }
        set
        {
            _title = value?.Trim();
        }
    }

    [Required(ErrorMessage = "Issuer Required")]
    [Display(Name="Issuer:")]
    [Column("audit_issuer_tx")]
    public string Issuer { get; set; }

    [Display(Name = "Sensitive Designation")]
    [Column("audit_sensitive_cd")]
    public string AuditSensitiveCode { get; set; }

    [Display(Name = "Alternative Product")]
    [Column("audit_alternate_product_cd")]
    public string AuditAlternateProductCode { get; set; }

    [RegularExpression("([1-9][0-9]*)", ErrorMessage = "Priority must be a number.")]
    [Display(Name = "Priority:")]
    [Column("audit_priority_cd")]
    public short? Priority { get; set; }

    [StringLength(maximumLength: 1000,ErrorMessage = "Max Length: 1000")]
    [Display(Name = "Summary:")]
    [Column("audit_summary_tx")]
    public string Summary
    {
        get
        {
            return _summary;
        }
        set
        {
            _summary = value?.Trim();
        }
    }

    [Column("audit_gao_contact_tx")]
    [Display(Name = "GAO Contact:")]
    [StringLength(maximumLength: 200, ErrorMessage = "Max Length: 200")]
    public string AuditGaoContactText { get; set; }

    [Column("audit_gao_job_cd")]
    [Display(Name = "GAO Job Code:")]
    [StringLength(maximumLength: 200, ErrorMessage = "Max Length: 30")]
    public string AuditGaoJobCode { get; set; }

    [Display(Name = "Lead Office:")]
    [Column("audit_lead_office_id")]
    public short? LeadOfficeID { get; set; }

    #region Navigation Properties
    [Required(ErrorMessage = "Audit Type Required.")]
    [Display(Name = "Audit Type:")]
    [Column("audit_audit_type_id")]
    public short AuditTypeID { get; set; }
    [Display(Name = "Audit Type:")]
    public AuditType AuditType { get; set; }

    [Column("audit_status_id")]
    public int StatusID { get; set; } 
    public Status Status { get; set; }

    [Required(ErrorMessage = "Office is Required.")]
    [Display(Name = "Offices:")]
    [Column("audit_office_id")]
    public short? OfficeID { get; set; }
    public Office Office { get; set; }

    [ForeignKey("AuditID")]
    public External External { get; set; }

    public IEnumerable<AuditLog> AuditLogs { get; set; }
    public IEnumerable<Finding> Findings { get; set; }
    public IEnumerable<Assignment> Assignments { get; set; }

    [Column("audit_update_staff_id")]
    public short UpdateStaffID { get; set; }

    [Column("audit_oig_manager_id")]
    [Display(Name = "OIG Audit Manager:")]
    public short? OigAuditManagerId { get; set; }
    [Display(Name = "OIG Audit Manager:")]
    [ForeignKey("OigAuditManagerId")]
    public Staff OigAuditManager { get; set; }

    [Column("audit_fsa_office_id")]
    [Display(Name = "FSA Audit Lead:")]
    public int? FsaLeadOfficeId { get; set; }
    [Display(Name = "FSA Audit Lead:")]
    [ForeignKey("FsaLeadOfficeId")]
    public FSAOffice FsaLeadOffice { get; set; }

    [ForeignKey("LeadOfficeID")]
    public Office LeadOffice { get; set; }
    #endregion
}

[Table("finding")]
public class Finding
{
    private string _findingText;

    [Key]
    [Column("finding_id")]
    public int FindingId { get; set; }

    [Column("finding_audit_id")]
    public int FindingAuditId { get; set; }

    [Column("finding_cd")]
    [Display(Name = "Finding #")]
    [StringLength(15)]
    public string FindingCd { get; set; }

    [Column("finding_tx")]
    [Required(ErrorMessage = "Description Required")]
    [StringLength(7000)]
    public string FindingText
    {
        get
        {
            return _findingText;
        }
        set
        {
            _findingText = value?.Trim();
        }
    }

    [Column("finding_page_cd")]
    [StringLength(100)]
    public string FindingPageCd { get; set; }

    [Column("finding_joint_cd")]
    public string FindingJointCd { get; set; }

    [Column("finding_compliance_tx")]
    [StringLength(20)]
    public string FindingComplianceText { get; set; }

    [Column("finding_prior_year_cd")]
    [Display(Name = "Repeat Finding")]
    public string FindingPriorYearCd { get; set; }

    [Column("finding_decision_cd")]
    public string FindingDecisionCd { get; set; }

    [Column("finding_request_decision_cd")]
    public string FindingRequestDecisionCd { get; set; }

    [Column("finding_decision_ogc_concur_cd")]
    public string FindingDecisionOgcConcurCd { get; set; }

    [Column("finding_pdl_id")]
    public int? FindingPdlId { get; set; }

    [Display(Name = "Significant")]
    [Column("finding_significant_cd")]
    public string FindingSignificantCd { get; set; }

    [Column("finding_on_stay_cd")]
    public string FindingOnStayCd { get; set; }

    [Column("finding_stay_request_cd")]
    public string FindingStayRequestCd { get; set; }

    [Column("finding_last_update_dt")]
    public DateTime FindingLastUpdateDate { get; set; }

    [Column("finding_update_staff_id")]
    public short? FindingUpdateStaffId { get; set; }

    [Column("finding_cd_org")]
    public string FindingCdOrg { get; set; }

    [NotMapped]
    public string RepeatingYearsDisplayList
    {
        get
        {
            if (RepeatingYears?.Count > 0)
            {
                string repeatingYears = string.Empty;
                RepeatingYears.ForEach(ry =>
                    repeatingYears += $"{ry.FindingFyCd}, ");
                return repeatingYears.Remove(repeatingYears.Length - 2);
            }
            return string.Empty;
        }
    }

    #region Navigation Properties
    [Column("finding_finding_type_id")]
    public short? FindingTypeId { get; set; }
    [ForeignKey("FindingTypeId")]
    public FindingType FindingType { get; set; }

    [Column("finding_status_id")]
    public int? FindingStatusId { get; set; }
    [ForeignKey("FindingStatusId")]
    public Status FindingStatus { get; set; }

    public List<FindingFiscalYear> RepeatingYears { get; set; }
    public List<Recommendation> Recommendations { get; set; }

    [ForeignKey("FindingAuditId")]
    public Audit Audit { get; set; }
    #endregion
}

A
Finding
имеет много Рекомендаций.

[Table("recommend")]
public class Recommendation
{
    private string _recText;

    [Key]
    [Column("recommend_id")]
    public int RecommendationId { get; set; }

    [Column("recommend_finding_id")]
    public int RecFindingId { get; set; }

    [Column("recommend_cd")]
    public short? RecCd { get; set; }

    [StringLength(7000)]
    [Column("recommend_tx")]
    public string RecText
    {
        get
        {
            return _recText;
        }
        set
        {
            _recText = value?.Trim();
        }
    }

    [Column("recommend_contact_nm")]
    public string RecContactName { get; set; }

    [Column("recommend_status_id")]
    public int RecStatusId { get; set; }

    [Column("recommend_recommend_type_cd")]
    public short? RecTypeCd { get; set; }

    [Column("recommend_staff_id")]
    public short RecStaffId { get; set; }

    [Column("recommend_role_id")]
    public short? RecRoleId { get; set; }

    [Column("recommend_oig_decision_cd")]
    public string RecOigDecisionCd { get; set; }

    [Column("recommend_last_update_dt")]
    public DateTime RecLastUpdateDt { get; set; }

    [Column("recommend_action_determination_cd")]
    public string RecActionDeterminationCd { get; set; }

    #region Navigation Properties
    [ForeignKey("RecFindingId")]
    public Finding Finding { get; set; }

    [ForeignKey("RecTypeCd")]
    public RecommendationType RecommendationType { get; set; }

    [ForeignKey("RecStatusId")]
    public Status RecommendationStatus { get; set; }

    [ForeignKey("RecStaffId")]
    public Staff Staff { get; set; }

    public List<Assignment> Assignments { get; set; }
    #endregion

    #region NOT Mapped
    [NotMapped]
    public string RecDisplayShortDesc => $"{RecCd} {RecText}";
    #endregion
}

Рекомендация может иметь много назначений:

[Table("assignment")]
public class Assignment
{
    [Key]
    [Column("assignment_id")]
    public int AssignmentId { get; set; }

    [Column("assignment_role_id")]
    public short AssignmentRoleId { get; set; }

    [Column("assignment_type_cd")]
    public string AssignmentTypeCd { get; set; }

    [Column("assignment_dt")]
    public DateTime AssignmentDate { get; set; }

    [Column("assignment_by_staff_id")]
    public short AssignmentByStaffId { get; set; }

    [Column("assignment_recommend_id")]
    public int? AssignmentRecommendId { get; set; }

    [Column("assignment_office_id")]
    public short? AssignmentOfficeId { get; set; } 

    #region Navigation Properties
    [Column("assignment_staff_id")]
    public short AssignmentStaffId { get; set; }
    [ForeignKey("AssignmentStaffId")]
    public Staff AssignmentStaff { get; set; }

    [Column("assignment_audit_id")]
    public int? AssignmentAuditId { get; set; }
    [ForeignKey("AssignmentAuditId")]
    public Audit Audit { get; set; }

    [ForeignKey("AssignmentOfficeId")]
    public Office AssignmentOffice { get; set; }

    [ForeignKey("AssignmentRecommendId")]
    public Recommendation Recommendation { get; set; }
    #endregion
}

У меня есть компонент View с запросом LINQ с использованием Any () метод полностью, начиная с коллекции Аудит верхнего уровня, чтобы получить все Аудиты с любыми Результатами, где в любом из Результатов, имеющих Рекомендации, где в какой-либо из этих рекомендаций отсутствует назначение с идентификатором роли 15 или 26. Если один из нихили обе эти записи назначения отсутствуют в записи, затем записи, результаты, аудит должны быть добавлены к коллекции аудита, возвращаемой в модель.

Мы думали, что это работает.Но затем мы заметили, что, когда есть только одна находка в ходе аудита, она не добавляется в коллекцию.Аудит неправильно добавляется, только если в результате аудита есть много выводов, а в одном из выводов есть запись с отсутствующим назначением.

Мне кажется, что это утверждение foreach работает:

        // Where audit has a recommendation without an assigned PO Authorizer
        //    OR without an assigned Responsible Manager (Rec Level).
        List<Audit> auditsToAssign = new List<Audit>();
        foreach (Audit audit in audits)
        {
            foreach (Finding finding in audit.Findings)
            {
                foreach (Recommendation rec in finding.Recommendations)
                {
                    if (!rec.Assignments.Any(asgn => asgn.AssignmentRoleId == 15)
                            || !rec.Assignments.Any(asgn => asgn.AssignmentRoleId == 26)
                        )
                    {
                        if (!auditsToAssign.Contains(rec.Finding.Audit))
                        {
                            auditsToAssign.Add(rec.Finding.Audit);
                        }
                    }
                }
            }
        }

Но изначально я пытался написать запрос LINQ.Это было через много итераций, но это текущая форма:

audits = audits.Where(a =>
            a.Findings.Count() > 0 &&
            a.Findings.Any(f =>
                f.Recommendations.Count() > 0 &&
                (
                !f.Recommendations.Any(r =>
                    r.Assignments.Any(asgn => asgn.AssignmentRoleId == 15)) ||
                !f.Recommendations.Any(r =>
                    r.Assignments.Any(asgn => asgn.AssignmentRoleId == 26))
                )
            )
        );

Ответы [ 2 ]

0 голосов
/ 30 мая 2018

Я думаю, что вы можете пойти в этом обратном направлении проще (при условии, что у вас есть ссылка на полную таблицу назначений):

var auditsToAssign = assignments.Where(asgn => asgn.AssignmentRoleId != 15 && asgn.AssignmentRoleId != 26)
                        .Select(asgn => asgn.Recommendation.Finding.Audit)
                        .Distinct();
0 голосов
/ 30 мая 2018

Я не уверен на 100%, что следовал вашему описанию, но попробуйте это:

        audits = audits.Where(a => 
                     a.Findings.Any(f => 
                         f.Recommendations.Any(r => 
                             !r.Assignments.Any(asgn => asgn.AssignmentRoleId == 15 || asgn.AssignmentRoleId == 26))));

Кроме того, Linq будет работать быстрее, чем ваш foreach, поскольку метод Any () перестанет перечислятькак только он найдет совпадение, тогда как ваши foreach продолжат перечислять всю коллекцию, даже если они найдут совпадение в самом начале.ИМХО также легче читать (хотя, когда вы начинаете с ним работать, требуется некоторое время, чтобы получить Linq-eye).

...