如何为数据库中不存在的记录填充具有默认值的列表?

时间:2018-06-26 14:01:34

标签: asp.net-mvc vb.net

我想在过去的一年中在数据库中进行记录,按月对记录求和,然后用该信息填充折线图。但是,当一个月没有记录时,我似乎无法弄清楚如何将其放入列表中的正确位置。例如,如果9月或10月不存在任何内容,则我的折线图将跳过这些月份。我尝试在之后检查并添加月份,但无法按顺序获取它们。有帮助吗?

Dim PointTotals = db.MemberRewards _
            .Where(Function(r) sitewideFilterSelectedMemberIds.Contains(r.memberId) And r.supplier.name <> "AudStandard" And r.transactionDate >= startDate And r.transactionDate <= EndDate) _
            .GroupBy(Function(r) New With {r.transactionDate.Value.Month, r.transactionDate.Value.Year}) _
            .Select(Function(gr) New With {.month = gr.Key.Month, .year = gr.Key.Year, .totalPoints = gr.Sum(Function(r) r.points)}) _
            .OrderBy(Function(gr) gr.year).ThenBy(Function(gr) gr.month)

Dim firstPeriodDate As Date
Dim currentDate As Date = DateAdd(DateInterval.Month, -1, startDate)

If PointTotals.Count > 0 Then
    Dim firstPeriod = PointTotals.First
    firstPeriodDate = CDate(firstPeriod.month & "/1/" & firstPeriod.year)
Else
    firstPeriodDate = EndDate
End If

Dim months As New List(Of String)
Dim Points As New List(Of Integer)
Do While currentDate < firstPeriodDate
    months.Add(currentDate.ToString("MMM"))
    Points.Add(0)
    currentDate = DateAdd(DateInterval.Month, 1, currentDate)
Loop

For Each period In PointTotals
    months.Add(CDate(period.month & "/1/" & period.year).ToString("MMM"))
    Points.Add(period.totalPoints)
Next

ViewBag.Months = """" & String.Join(""",""", months.ToArray) & """"
ViewBag.Points = String.Join(",", Points.ToArray)

3 个答案:

答案 0 :(得分:0)

听起来像在您的代码中添加使用.Add方法的缺少月份。您将需要使用months.Insert(position,CDate(....))和Points.Insert(position,0),其中position是正确的索引,可以按正确的顺序插入月份。

我可以给您确切的命令,但是您没有包含问题中引用的清理代码。

答案 1 :(得分:0)

您可以采用许多方法来解决此问题,我将提供一个数据库。

由于要连接到数据库以提取数据,所以您也可以在数据库端进行求和/分组。

您可以通过3个步骤进行操作: 1)获得所有月份的明确列表,并将它们存储在临时表中 2)按月创建汇总,并将其存储在另一个临时表中 3)在步骤2中离开加入步骤1(使用月份作为加入条件),按照您关心的顺序进行订购,现在您已经拥有了所有月份。

有很多方法可以在SQL端实现这一点,上面的方法只是我认为很容易遵循的一种方法。

答案 2 :(得分:0)

与循环后尝试清理列表相比,我认为这是一种更优雅的解决方案。对代码的唯一更改是在“每个周期”循环之前和之中。

Dim PointTotals = db.MemberRewards _
        .Where(Function(r) sitewideFilterSelectedMemberIds.Contains(r.memberId) And r.supplier.name <> "AudStandard" And r.transactionDate >= startDate And r.transactionDate <= EndDate) _
        .GroupBy(Function(r) New With {r.transactionDate.Value.Month, r.transactionDate.Value.Year}) _
        .Select(Function(gr) New With {.month = gr.Key.Month, .year = gr.Key.Year, .totalPoints = gr.Sum(Function(r) r.points)}) _
        .OrderBy(Function(gr) gr.year).ThenBy(Function(gr) gr.month)

        Dim firstPeriodDate As Date
        Dim currentDate As Date = DateAdd(DateInterval.Month, -1, startDate)

        If PointTotals.Count > 0 Then
            Dim firstPeriod = PointTotals.First
            firstPeriodDate = CDate(firstPeriod.month & "/1/" & firstPeriod.year)
        Else
            firstPeriodDate = EndDate
        End If

        Dim months As New List(Of String)
        Dim Points As New List(Of Integer)
        Do While currentDate < firstPeriodDate
            months.Add(currentDate.ToString("MMM"))
            Points.Add(0)
            currentDate = DateAdd(DateInterval.Month, 1, currentDate)
        Loop

        Dim thisPeriodDate As Date
        Dim previousPeriodDate As Date = currentDate
        For Each period In PointTotals
            thisPeriodDate = CDate(period.month & "/1/" & period.year)
            Do While DateDiff(DateInterval.Month, previousPeriodDate, thisPeriodDate) > 1
                months.Add(previousPeriodDate.ToString("MMM"))
                Points.Add(0)
                previousPeriodDate = DateAdd(DateInterval.Month, 1, previousPeriodDate)
            Loop
            months.Add(thisPeriodDate)
            Points.Add(period.totalPoints)
            previousPeriodDate = DateAdd(DateInterval.Month, 1, previousPeriodDate)
        Next

        ViewBag.Months = """" & String.Join(""",""", months.ToArray) & """"
        ViewBag.Points = String.Join(",", Points.ToArray)