代码之家  ›  专栏  ›  技术社区  ›  Whirlwind

使用日期选择器和实体框架6获取两个日期之间的所有日期

  •  0
  • Whirlwind  · 技术社区  · 7 年前

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

    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实体中不受支持。仅支持初始值设定项、实体成员和实体导航属性。”

    如何做到这一点?

    1 回复  |  直到 7 年前
        1
  •  1
  •   Harald Coppoolse    7 年前

    错误消息的原因

    IEnumerable IQueryable

    实现的类的对象 数不清 保存要在其所表示的项序列上枚举的所有内容。你可以要求序列的第一项,一旦你有了一项,你可以要求下一项,直到没有更多的项目。

    易变的 保存所有内容以请求另一个进程提供数据以创建IEnumerable序列。要做到这一点,它需要 Expression Provider .

    这个 是一种泛型表示,表示在开始枚举 易变的 .

    这个 供应商 表示 转换为执行者理解的格式,例如SQL。

    IQueryable<TResult> (或可数的)。例如 Where , Select , GroupBy

    非延迟函数返回一个 TResult : ToList ToDictionary , FirstOrDefault , Max .

    只要连接延迟LINQ函数,查询就不会执行,只有 表示 改变了。一旦开始枚举,可以显式使用 GetEnumerator MoveNext ,或隐式使用foreach、ToList、Max等 表示 已发送到 供应商 谁将把它转换成SQL并执行查询。结果表示为 数不清 ,而 执行。

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

    因为 表示 必须翻译成SQL,它不能容纳你发明的任何东西。毕竟,SQL不知道您的函数。事实上,有很多标准函数不能在应用程序中使用 易变的 . 看见 Supported and unsupported LINQ functions

    唉,你忘了给我们钱 archive 类定义,但我认为它不是POCO:它包含的函数和属性不仅仅是get/set。我认为 IssuingDate

    对于IQueryables,您应该使类保持简单:仅使用 {get; set;} 在您的查询过程中,仅此而已。其他函数可以在具体化后调用 易变的 数不清 这将在您的本地流程中执行

    回到你的问题上来

    Archive 至少包含列 发行日期 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标准,特别是复数和驼峰式大小写,有什么正当的原因吗?

    不管怎样,你的要求

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

    您的代码似乎做得更多,但让我们首先编写一个满足您需求的扩展函数。我将把它作为归档类的扩展方法来编写。这将使归档类保持简单(仅限 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);
    }
    

    如果我看一下您的代码,您不会在日期之间选择归档。您可以使用用户名、排序、选择distinct。。。有点奇怪的是,您首先订购了所有一百万份档案,然后决定只保留属于userName的十份档案,如果您有几个相同的发行日期,则决定删除重复的档案。在开始订购之前,先限制发行日期不是更有效吗?

    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);
    }
    

    表示

    用法示例:

    要求:给定用户名、开始日期和结束日期,按升序提供该用户发布的所有归档文件的唯一发布日期

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