【问题标题】:How to use the let clause in C#如何在 C# 中使用 let 子句
【发布时间】:2020-08-19 11:24:46
【问题描述】:

下面的代码在 LINQPad 中完美运行,但是当我在 Visual Studio 中实现它时,它不会提取任何数据。当我评论 let 子句和周期(1 到 5)时,我得到了所有其他数据(Pin ...Notes)。有人可以告诉我如何在 C# 中实现 let 子句吗?

public List<RouteStatus> Route_AB_List(int yardId, int siteTypeId)
{
    using (var context = new COESystemContext())
    {
        var RouteList = from site in context.Sites
                           where site.YardID == yardId && site.SiteTypeID == siteTypeId && site.Season.SeasonYear == DateTime.Now.Year
                           orderby site.Community.Name ascending
                           let Cycles = site.JobCards
                                               .Where(job => job.OperationID == 1)
                                               .OrderByDescending(job => job.ClosedDate.HasValue)
                                               .ThenBy(job => job.ClosedDate)
                                               .Select(job => new { Date = job.ClosedDate })
                           select new RouteStatus
                           {
                               Pin = site.Pin,
                               Community = site.Community.Name,
                               Neighbourhood = site.Neighbourhood,
                               Address = site.StreetAddress,
                               Area = site.Area,
                               Notes = site.Notes,
                               Cycle1 = Cycles.FirstOrDefault().Date,
                               Cycle2 = Cycles.FirstOrDefault().Equals(null) ? (DateTime?)null : Cycles.Skip(1).FirstOrDefault().Date,
                               Cycle3 = Cycles.Skip(2).FirstOrDefault().Equals(null) ? (DateTime?)null : Cycles.Skip(2).FirstOrDefault().Date,
                               Cycle4 = Cycles.Skip(3).FirstOrDefault().Equals(null) ? (DateTime?)null : Cycles.Skip(3).FirstOrDefault().Date,
                               Cycle5 = Cycles.Skip(4).FirstOrDefault().Equals(null) ? (DateTime?)null : Cycles.Skip(4).FirstOrDefault().Date
                           };
        return RouteList.ToList();

    }
}

【问题讨论】:

  • 所以问题不在于如何使用let 子句。目前尚不清楚“在 Linq 中”和“在 VisualStudio 中”是什么意思。重要的是在这两种情况下您连接到哪个数据库以及哪个 ORM 执行该语句。
  • 对不起,我的意思是在 LinqPad 中,代码运行完美,但是当我在 VisualStudio 中实现它时,它没有返回任何数据
  • @J.RaoulFEZE - 然后编辑您的问题。

标签: c# asp.net linq


【解决方案1】:

在我看来,您对每个 Cycle1 到 Cycle5 执行一次选择-where-order 循环。

此外,如果 FirstOrDefault 的结果为空,您必须做一些困难的事情。

我的建议是使用更多选择来优化您的代码。

更小的步骤:

var selectedSitesAndCycles = dbContext.Sites

    // keep only those sites that ...
    .Where(site => site.YardID == yardId
                && site.SiteTypeID == siteTypeId
                && site.Season.SeasonYear == DateTime.Now.Year)

    // order the remaining sites in ascending order by name
    .OrderBy(site => site.Community.Name)

    // from every ordered site, get some properties and a list of 5 cycles:
    .Select(site => new
    {
        Pin = site.Pin,
        Community = site.Community.Name,
        Neighbourhood = site.Neighbourhood,
        Address = site.StreetAddress,
        Area = site.Area,
        Notes = site.Notes,

        ClosedDates = site.JobCards
            .Where(job => job.OperationID == 1)
            .OrderByDescending(job => job.ClosedDate.HasValue)
            .ThenBy(job => job.ClosedDate)
            .Select(job => Date = job.ClosedDate)
            .Take(5)
            .ToList(),
    });

请注意查询尚未执行。我只需要5个周期。选择 ClosedDate 时,我没有使用关键字 new。因此 CycleClosedDates 是一个List&lt;DateTime?&gt;。

换句话说:CycleClosedDates 的每个元素都是可以为空的 DateTime。如果您选择FirstOrDefault,您将获得第一个可为空的 DateTime,它可能是 DateTime 或 null,或者如果没有足够的 CycleClosedDates,您将获得 (DateTime?)null。

让我们来看看一个站点只有三个 JobCard 的情况:

JobCard[0] is closed and has ClosedDate 2020-03-10
JobCard[1] is not closed yet. ClosedDate isn (DateTime?)null
JobCard[3] is closed and has ClosedDate 2020-03-20
// There is no JobCard[4] [5]

结果是List&lt;DateTime?&gt;,长度为 3,其中元素 [1] 没有值。 Skip(1).FirstOrDefault() 的结果将是一个没有值的可为空的 DateTime。

好消息是Skip(4).FirstOrDefault() 也将是一个没有值的可为空的 DateTime,即使没有 5 个 JobCard

让我们继续使用额外的 Select 来创建您的五个属性:

    .Select(site => new
    {
        Pin = site.Pin,
        Community = site.Community.Name,
        Neighbourhood = site.Neighbourhood,
        Address = site.StreetAddress,
        Area = site.Area,
        Notes = site.Notes,

        Cycle1 = site.CycleClosedDates.FirstOrDefault(),
        Cycle2 = site.CycleClosedDates.Skip(1).FirstOrDefault(),
        Cycle3 = site.CycleClosedDates.Skip(2).FirstOrDefault(),
        ...
    })

请注意,CycleClosedDates 只会订购一次。因为 CycleClosedDates 已经是一个List&lt;DateTime?&gt;,所以创建单独的属性而不是一个长度为 5 的列表似乎有点多余。在您的第二次选择中考虑

.Select(site => new
{
    Pin = site.Pin,
    Community = site.Community.Name,
    ...

    CycleClosedDates = new List[]
    {
        site.CycleClosedDates.FirstOrDefault(),
        site.CycleClosedDates.Skip(1).FirstOrDefault(),
        site.CycleClosedDates.Skip(2).FirstOrDefault(),
        ...
    },
};

或者在第一次选择之后:

// move the selected data to local process
.AsEnumerable()
// 2nd select:
    .Select(site => new
{
    Pin = site.Pin,
    Community = site.Community.Name,
    ...

    CycleClosedDates = site.CycleClosedDates
        .Concat(Enumerable.Repeat( (DateTime?)null, 5)
        .Take(5)
        .ToList();

这样您就可以确定您的 CycleClosedDates 恰好有五个可为空的 DateTime,即使根本没有 JobCard。

【讨论】:

  • 谢谢让我试试
  • 你好先驱报。谢谢你的帮助。您提供的代码有效。我仍然试图围绕代码'''//将选定的数据移动到本地进程'''。非常感谢
  • AsEnumerable 只有在另一个进程(如数据库管理系统)正在执行您的查询并且您想使用自己的方法时才需要。 AsEnumerable 将以一种智能的方式执行查询(通常:不要一次获取所有数据,而是“根据需要每页”)。在 AsEnumerable 之后,您可以使用 IQueryable 不支持的本地方法和 Enumerable LINQ 方法,例如 Enumerable.Repeat。缺点:DBMS 在加入、排序、选择等方面比你的程序更优化。让 DBMS 尽可能多地使用 = 尽可能晚地使用 AsEnumerable。
  • 感谢 Harald 的洞察力。我真的很感激。
猜你喜欢
  • 1970-01-01
  • 2018-09-16
  • 1970-01-01
  • 2018-12-16
  • 1970-01-01
  • 1970-01-01
  • 2012-04-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多