【问题标题】:Getting all dates between two dates using datepickers and Entity Framework 6使用日期选择器和实体框架 6 获取两个日期之间的所有日期
【发布时间】:2019-05-11 20:13:09
【问题描述】:

我的表单上有两个日期时间选择器。我想要一个函数,它将返回这两个日期之间特定表(它们是特定列的值)的所有日期时间。

我的方法是这样的:

public DateTime[] GetAllArchiveDates(string username = null)
{
    var result = new DateTime[0];

    if (username != null)
    {
        result = this._context.archive.OrderBy(s => s.IssuingDate).Where(s => s.insertedBy == username).Select(s => s.issuing_date).Distinct().ToArray();
    }
    else
    {
        result = this._context.archive.OrderBy(s => s.IssuingDate).Select(s => s.issuing_date).Distinct().ToArray();
    }

    return result;
}

但我收到此错误:

System.NotSupportedException: '指定类型成员'IssuingDate' 在 LINQ to Entities 中不受支持。仅支持初始化程序、实体成员和实体导航属性。'

如何做到这一点?

【问题讨论】:

  • OrderBy 中有s.IssuingDate,但在Select 中有s.issuing_date
  • s.IssuingDates.issuing_date有什么区别?
  • @HandbagCrab 哦,就是这样。 s.IssuingDate 是通过部分类添加的字符串类型的属性,它是该日期的文本表示......我的错......谢谢!
  • 不客气。

标签: c# winforms entity-framework linq entity-framework-6


【解决方案1】:

错误信息的原因

您应该了解IEnumerableIQueryable 之间的区别。

实现IEnumerable 的类的对象包含要枚举它所代表的项目序列的所有内容。您可以请求序列中的第一项,一旦获得了一项,您就可以请求下一项,直到没有更多项为止。

另一方面,实现IQueryable 的类的对象拥有一切要求另一个进程提供数据以创建 IEnumerable 序列。为此,它拥有一个Expression 和一个Provider

Expression 是在开始枚举IQueryable 后必须创建哪种 IEnumerable 的通用表示。

Provider 知道谁必须执行查询,它知道如何将Expression 转换为执行程序可以理解的格式,例如 SQL。

有两种 LINQ 语句。那些使用延迟执行的,以及那些不使用的。可以识别延迟函数,因为它们返回 IQueryable<TResult>(或 IEnumerable)。例如WhereSelectGroupBy 等。

非延迟函数返回TResultToListToDictionaryFirstOrDefaultMax

只要连接延迟的 LINQ 函数,就不会执行查询,只会更改 Expression。一旦开始枚举,无论是显式使用GetEnumeratorMoveNext,还是隐式使用foreach、ToList、Max 等,Expression 都会发送到ProviderProvider 会将其转换为SQL 并执行查询。结果表示为IEnumerable,在其上执行GetEnumerator

这与我的问题有什么关系?

因为Expression 必须被翻译成SQL,它不能容纳你发明的任何东西。毕竟,SQL 不知道你的函数。事实上,IQueryable 中不能使用很多标准函数。见Supported and unsupported LINQ functions

唉,你忘了给我们archive 类定义,但我认为它不是 POCO:它包含的功能和属性不仅仅是获取/设置。我认为IssuingDate 不只是获取/设置。

对于 IQueryables,您应该保持类简单:在查询期间仅使用 {get; set;},仅此而已。在将 IQueryable 物化为要在本地进程中执行的 IEnumerable 后,可以调用其他函数

回到你的问题

所以你有一个数据库,其中有一个表Archive,其中至少有IssuingDateInsertedBy 列。似乎InsertedBy 只是一个字符串。它可能是用户表的外键。这不会对答案产生太大影响。

按照entity framework code first conventions 这会导致以下类

class Archive
{
    public int Id {get; set;}
    public DateTime IssuingDate {get; set;}
    public string InsertedBy {get; set;}
    ...
}

public class MyDbContext : DbContext
{
     public DbSet<Archive> Archives {get; set;}
}

顺便说一句,您经常偏离 Microsoft 关于命名标识符的标准,尤其是复数和驼峰式大小写,是否有正当的理由?

不管怎样,你的要求

我的表单上有两个日期时间选择器。我想要一个函数,它将返回这两个日期之间特定表(即特定列的值)中的所有日期时间。

您的代码似乎做得更多,但让我们先编写一个满足您要求的扩展函数。我会把它写成你归档类的扩展方法。这将使您的存档类保持简单(仅{get; set;}),但它为类添加了功能。将其编写为扩展函数还使您能够像使用任何其他 LINQ 函数一样使用这些函数。见Extension methods demystified

public static IQueryable<Archive> BetweenDates(this IQueryable<Archive> archives,
    DateTime startDate,
    DateTime endDate)
{
     return archives.Where(archive => startDate <= archive.IssuingDate
                                   && archive.IssuingDate <= endDate);
}

如果我查看您的代码,您不会在日期之间选择档案。你用一个用户名做一些事情,排序,选择不同的…有点奇怪,你先订购所有的百万档案,然后决定只保留属于用户名的十个档案,如果你有几个相同的发布日期您决定删除重复项。在开始订购之前先限制发行日期的数量不是更有效吗?

public static IQueryable<archive> ToIssuingDatesOfUser(this IQueryable<archive> archives,
    string userName)
{
    // first limit the number of archives, depdning on userName,
    // then select the IssuingDate, remove duplicates, and finally Order
    var archivesOfUser = (userName == null) ? archives :
        archives.Where(archive => archive.InsertedBy == userName);

   return archivesOfUser.Select(archive => archive.IssuingDate)
                        .Distinct()
                        .OrderBy(issuingDate => issuingDate);
}

注意:到目前为止,我只创建了 IQueryables。所以只更改了Expression,这是相当有效的。数据库尚未通信。

使用示例:

要求:给定一个用户名、一个开始日期和一个结束日期,给我这个用​​户发布的所有档案的唯一发布日期,按升序排列

public ICollection<string> GetIssuingDatesOfUserBetweenDates(string userName, 
    DateTime startDate,
    DateTime endDate)
{
    using (var dbContext = new MyDbContext(...))
    {
        return dbContext.Archives
               .BetweenDates(startDate, endDate)
               .ToIssuingDatesOfUser(userName)
               .ToList();
    }
}

【讨论】:

  • 您好,感谢您提供详细而有用的回答。我想我会听从你关于性能的建议!
猜你喜欢
  • 1970-01-01
  • 2018-12-26
  • 2013-08-09
  • 1970-01-01
  • 2017-06-12
  • 1970-01-01
  • 2018-01-11
  • 1970-01-01
  • 2014-06-11
相关资源
最近更新 更多