C#Group通过麻烦

时间:2019-06-04 13:32:06

标签: c# entity-framework-core

到目前为止,我正在尝试创建一个根据特定条件进行分组的列表,然后在视图中显示该列表。

我有两个数据库表,一个是关联表。

第一张表

<?php if ( get_current_user_id() != 0 ) : ?>

第二张表(关联表)

public partial class InitialTraining
{
    public InitialTraining()
    {
        InitialTrainingAssociations = new HashSet<InitialTrainingAssociation>();
    }
    public int Id { get; set; }

    [ForeignKey("MedicInfo")]
    public int TfoId { get; set; }

    [ForeignKey("InstructorInfo")]
    public int? InstructorId { get; set; }

    [ForeignKey("PilotInfo")]
    public int? PilotId { get; set; }

    public DateTime DateTakenInitial { get; set; }

    public decimal FlightTime { get; set; }

    public bool Active { get; set; }

    [StringLength(2000)]
    public string Narrative { get; set; }

    [Required]
    [StringLength(20)]
    public string TrainingType { get; set; }

    [ForeignKey("CodePhase")]
    public int PhaseId { get; set; }

    [ForeignKey("PhaseTrainingType")]
    public int PhaseTrainingTypeId { get; set; }
    public string EnteredBy { get; set; }
    public DateTime? EnteredDate { get; set; }

    public virtual MedicInfo MedicInfo { get; set; }
    public virtual MedicInfo InstructorInfo { get; set; }
    public virtual MedicInfo PilotInfo { get; set; }
    public virtual Code_Phase CodePhase { get; set; }
    public virtual Code_PhaseTrainingType PhaseTrainingType { get; set; }
    public virtual ICollection<InitialTrainingAssociation> InitialTrainingAssociations { get; set; }
}

这是我在C#中的public class InitialTrainingAssociation { public int Id { get; set; } [ForeignKey("InitialTraining")] public int InitialTrainingId { get; set; } [ForeignKey("CodePerformanceAnchor")] public int? PerformanceAnchorId { get; set; } [ForeignKey("GradingSystem")] public int? GradingSystemId { get; set; } public virtual AviationMedicTraining.CodePerformanceAnchor CodePerformanceAnchor { get; set; } public virtual InitialTraining InitialTraining { get; set; } public virtual GradingSystem GradingSystem { get; set; } }

GroupBy

我的目标

很明显,从我的代码中,我想按关联表中的性能锚点分组,但是我需要从// get list of initial training record ids for statistics var lstInitialTrainings = db.InitialTrainings.Where(x => x.TfoId == medicId && x.Active).Select(x => x.Id).ToList(); // get list of initial training performance anchors associated with initial training records var lstPerformanceAnchors = db.InitialTrainingAssociations .Where(x => lstInitialTrainings.Contains(x.InitialTrainingId)).GroupBy(t => t.PerformanceAnchorId) .Select(s => new MedicStatistic() { PerformanceAnchorName = db.CodePerformanceAnchor.FirstOrDefault(v => v.Id == s.Key).PerformanceAnchor, AnchorCount = s.Count() }).ToList(); 表中获取更多信息,以将其包含在ViewModel Initial Training中,但是我在确定时遇到了麻烦找出最好的方法。

我的总体目标是能够从MedicStatistic表中获取性能锚定的最新时间。

视觉

初始培训表(并非所有片段均在摘录b / c中捕获,对于此问题而言,它们并不重要)

enter image description here

初始培训关联表

enter image description here


我期望的结果

因此,从上面提供的图片中可以看到,关联表中有多个Initial Training用于性能锚点ID,但是它们各自具有不同的1 。因此,此特定性能锚已经完成了多次,但我需要从InitialTrainingId表中获取最新日期。另外,我需要根据最近的日期从Initial Training表中获取带有锚点的相应成绩。

因此,对于等于Grading System的性能锚点。我想要与1的{​​{1}}对应的等级,因为该记录是性能锚点最近的时间InitialTrainingId中的内容已完成。

如果您有任何疑问,请告诉我。

3 个答案:

答案 0 :(得分:2)

您希望按CodePerformanceAnchor对数据进行分组,因此开始查询的最自然的方法是在其DbSet处,这立即消除了分组的必要性:

from pa in db.CodePerformanceAnchors
let mostRecentInitialTraining
    = pa.InitialTrainingAssociations
        .Select(ita => ita.InitialTraining)
        .OrderByDescending(tr => tr.DateTakenInitial)
        .FirstOrDefault()
select new 
{
    pa.PerformanceAnchor,
    mostRecentInitialTraining.DateTakenInitial,
    mostRecentInitialTraining. ...
    ...
    AnchorCount = pa.InitialTrainingAssociations.Count()
}

如您所见,仅使用导航属性,整个查询非常简单。我假设PerformanceAchor类也有一个InitialTrainingAssociations集合。

尽管我不能保证EF能够完全在服务器端执行它,但是对于更复杂的LINQ查询来说,这总是很棘手的事情。

答案 1 :(得分:1)

我将忽略您的virtual类中的InitialTrainingAssociation属性,因为您没有提及任何有关它们的内容,而且对于它们是否真正包含数据或为什么包含它们,我也不是很清楚是virtual

似乎IQueryable.Join是合并所需数据的最简单方法。

在下面的示例中,我们将从InitialTrainings表中的条目开始。然后,我们将Join与InitialTrainingAssociations表一起使用,这将导致成对的InitialTraining和InitialTrainingAssociation对象的集合。

var initialTrainingResults =
    // Start with the InitialTrainings data.
    db.InitialTrainings

    // Add association information.
    .Join(
        // The table we want to join with
        db.InitialTrainingAssociations,

        // Key selector for the outer type (the type of the collection
        // initiating the join, in this case InitialTraining)
        it => it.Id,

        // Key selector for the inner type (the type of the collection
        // being joined with, in this case InitialTrainingAssociation)
        ita => ita.InitialTrainingId,

        // Result selector. This defines how we store the joined data.
        // We store the results in an anonymous type, so that we can
        // use the intermediate data without having to declare a new class.
        (InitialTraining, InitialTrainingAssociation) =>
            new { InitialTraining, InitialTrainingAssociation }
    )

从这里,我们可以通过执行更多Join来添加PerformanceAnchors和GradingSystems表中的数据。每次执行Join时,都会向匿名类型添加一个新实体。结果将是匿名类型的集合,这些匿名类型表示我们从数据库中检索到的数据。

    // Add performance anchor information.
    .Join(
        db.PerformanceAnchors,
        x => x.InitialTrainingAssociation.PerformanceAnchorId,
        pa => pa.Id,
        (x, PerformanceAnchor) =>
            new { x.InitialTrainingAssociation, x.InitialTraining, PerformanceAnchor }
    )

    // Add grading system information.
    .Join(
        db.GradingSystems,
        x => x.InitialTrainingAssociation.GradingSystemId,
        gs => gs.Id,
        // No need for InitialTrainingAssociation anymore, so we don't
        // include it in this final selector.
        (x, GradingSystem) =>
            new { x.InitialTraining, x.PerformanceAnchor, GradingSystem }
    );

(这是一个冗长的示例,展示了如何将所有表连接在一起。如果不需要一次访问所有数据,则可以使用较少的Joins,并且可以过滤InitialTrainings集合首先,如果您知道您只需要访问某些数据。)

这时,initialTrainingResults是一个IEnumerable,其中包含InitialTrainings,PerformanceAnchors和GradingSystems表之间每个关联的一个条目。本质上,我们所做的就是获取所有InitialTrainingAssociations并将其ID扩展为实际对象。

要获取每个性能锚点的最新数据集:

var performanceAnchors = initialTrainingResults
    // Group by each unique Performance Anchor. Remember, the IEnumerable
    // we are operating on contains our anonymous type of combined Training,
    // Performance Anchor and Grading data.
    .GroupBy(x => x.PerformanceAnchor.Id)

    // Order each Performance Anchor group by the dates of its training,
    // and take the first one from each group
    .Select(g => g.OrderByDescending(x => x.InitialTraining.DateTakenInitial).First());

答案 2 :(得分:0)

Select中,您可以命令分组结果以InitialTraining的形式获取最新的关联DateTakenInitial,然后从中获取所需的数据

//...omitted for brevity
.GroupBy(t => t.PerformanceAnchorId)
.Select(g => {

    var mostRecent = g.OrderByDescending(_ => _.InitialTraining.DateTakenInitial).First();
    // get the corresponding grade with the anchor from the Grading System table
    var gradeid = mostRecent.GradingSystemId;
    var gradingSystem = mostRecent.GradingSystem;

    //get the most recent date from the Initial Training
    var mostRecentDate = mostRecent.InitialTraining.DateTakenInitial

    //..get the desired values and assign to view model

    var model = new MedicStatistic {
        //Already have access to CodePerformanceAnchor
        PerformanceAnchorName = mostRecent.CodePerformanceAnchor.PerformanceAnchor
        AnchorCount = g.Count(),
        MostRecentlyCompleted = mostRecentDate,
    };

    return model;
});