【问题标题】:C#/EF Core: Working with (historical) dates/periodsC#/EF Core:使用(历史)日期/期间
【发布时间】:2019-07-03 14:35:20
【问题描述】:

给定一个使用 SQL Server 和 EF Core 的 ASP.NET Core Mvc 的 C# 网站。

对于一个爱好项目,我正在查看旧报纸、文件并寻找特定的建筑物。每次我找到此类建筑物的信息时,我都会尝试写下日期信息。这样我就可以跟踪这座建筑是在哪个时期存在的。

假设我遇到 Build X 并看到日期 1880。我记下日期1880。 几周后,我再次遇到 X 楼,看到日期:1877 年 3 月 16 日。我现在知道这座建筑从 1877 年 3 月 16 日到 1880 年肯定在那里。

时期:16/03/1877 - 1880

  • 现在有些建筑物没有任何日期信息。
  • 有些建筑物只有一个日期(也许通过额外的研究可以找到另一个)
  • 某些建筑物可能有其存在于 17 世纪的信息(没有具体的年份或日期)。
  • 日期可以包含年、年+月或年+月+日

现在最好将它存储在数据库中并在模型中表示它。

一个模型上的 2 个属性就足够了吗?

public class Building {
[DataType(DataType.Date)]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
  public DateTime? Date1 { get; set; }
[DataType(DataType.Date)]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime? Date2 { get; set; }
}

它是否适合网站上的搜索过滤器。例如。搜索 1830 年至 1930 年间的一切或 17 世纪的一切。

关于最后一个问题,我的意思是,如果建筑物只有一个日期(例如 1835 年),您将如何编写 linq 查询。如果只给出一个日期,每个查询是否会包含对可空日期的额外检查?还是有更好的方案?

.Where(x => x.Date1 != null && x.Date1 >= 1830 && (x.Date2 == null || x.Date2 <= 1930))

或者正在保存一个日期时间?对象不是一个好主意,最好存储一个短整数或整数,并且只跟踪年份组件(如果有的话)?

【问题讨论】:

  • 一年我会说您的日期是从 1 月 1 日到 12 月 31 日,直到您遇到建筑物被摧毁或建造的日期,这可能会调整该范围的任一端。对于单个日期,只需将两者都设置为该单个日期。
  • 这取决于您将保存的有关建筑物的其他属性...如果您只想知道建筑物是否在特定日期时间在这里,所以如果新的日期是年纪大了。如果您想跟踪建筑物的生命周期(创建、火灾、破坏......),您应该查看事件溯源martinfowler.com/eaaDev/EventSourcing.html
  • 这是高度基于意见的。

标签: c# asp.net-core-mvc entity-framework-core database-schema


【解决方案1】:

真的,您的问题归结为显示确切日期与“模糊”日期。没有一个单一的策略,但我之前有过类似的要求,并通过设置开始日期、模糊开始、结束日期和模糊结束来处理它,所有这些都可以为空。

如果您完全知道日期的任何确切部分,则使用实际的日期时间字段。例如,如果您只知道 1880,则将其存储为 1880-01-01。如果您知道年份和月份,则只需将日期设为01,当然,如果您知道完整日期,则将其存储。现在,当然,这可能是有问题的。你怎么知道它实际上不是在 1880 年 1 月 1 日建造的,而只是一般意义上的 1880 年?好吧,这取决于您决定如何处理这些情况。您可以假设任何01 与该日期部分的空值相同。无论出于何种原因,建筑物往往不会在 1 月 1 日或实际上任何一个月的 1 日开放,但总有例外。

如果您确实需要更高的精度,您可能需要将日期分开并将其按字面意思存储为年、月和日 - 所有可为空的 int 列。然后,您可以在需要显示时随意拼凑。

“模糊”日期列将是字符串,您可以在其中存储更多星云“日期”,例如“维多利亚时代”,即您可能没有真实的日期甚至年份,但您知道那是在某个时期的时间。您可以对“19 世纪”之类的内容执行相同的操作,但我个人更喜欢将其存储为 1800-01-01,然后直觉认为当有该形式的日期时它应该显示为“19 世纪”。

另一种选择是同时使用日期和模糊文本。例如,您可以将其存储为 1800-01-01 “19 世纪”,然后您可以根据模糊文本的存在来确定它不是字面上的 1800 年 1 月 1 日不为空。这可以帮助解决前面描述的歧义问题,因为您可以对所有此类情况执行此操作。例如,如果您只知道“1880 年 7 月”,那么您可以将其存储在模糊文本中,并将日期设置为 1880-07-01。然后,根据模糊文本的存在,您可以选择将01 部分解读为基本上为空,而不是字面上的第一个月。如果没有设置模糊文本,那么您会认为它是一个确切的日期。

就在您的模型上表示它而言,我不会使用实际的DateTime 属性或DisplayFormat。拥有可以处理逻辑并返回预先格式化的“日期”的实用方法会更好地为您服务。然后您只需执行@building.GetBuiltDisplay() 之类的操作,并返回您知道的所有信息(包括开始和结束,如果有的话)。

【讨论】:

  • 在我最近看的一个更有趣的项目中,他们以非常有趣的方式做到了这一点:int Century,int?年,日期时间2?准确日期。如果世纪和/或年份已知,则确切日期并不重要(可以通过已知数据进行广泛过滤)。当然它会占用更多空间,但比处理任意日期(如 1899-12-31 左右)要容易得多。编辑:项目是用于历史项目跟踪的个人收集系统。
  • @ChrisPratt:“年、月和日 - 所有可为空的 int 列。”为什么不 ushort,字节,字节?
猜你喜欢
  • 2021-03-09
  • 2018-02-08
  • 2018-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-22
  • 2016-10-24
相关资源
最近更新 更多