是否可以直接在NHibernate中设置引用的外键?

Run*_*sen 2 nhibernate fluent-nhibernate dimensional-modeling

有一个项目从特定系统收集数据作为XML文件(这些文件作为Web请求进入),将其转换为实体模型,并将其填充到数据库中进行报告.

该项目使用以下软件(与此问题相关):

  • C#4.0/.Net 4
  • NHibernate 3.0(最新的NuGet版本)
  • 流利的NHibernate(与NH 3一起使用的那个)

假设我有这样的实体(简化):

public class Incident : Entity
{
        public virtual string OriginatorSite { get; set; }
        public virtual string DestinationSite { get; set; }
        public virtual IncidentType IncidentType { get; set; }
        public virtual TimeSpan TotalWaitTime { get; set; }
        public virtual TimeSpan TotalActionTime { get; set; }
        public virtual DateTime RegisterTime { get; set; }
        public virtual DateTime CloseTime { get; set; }
        public virtual DateDimension DateDimension { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这就是这样映射的:

public class IncidentMap : ClassMap<Incident>
{
    public IncidentMap()
    {
        Id(c => c.Id);

        Map(c => c.OriginatorSite);
        Map(c => c.DestinationSite);
        Map(c => c.IncidentType).CustomType<IncidentType>();
        Map(c => c.TotalWaitTime);
        Map(c => c.TotalActionTime);
        Map(c => c.RegisterTime);
        Map(c => c.CloseTime);

        References<DateDimension>(c => c.DateDimension);
    }
}
Run Code Online (Sandbox Code Playgroud)

(Id来自Entity基类)

由于那些处理这些事情的人可能已经从代码中读过,我试图在这里做一些维度建模.我是这个主题的新手,并且在所有可能的情况下做错了(但是)我希望至少从这种方式中获得一些好处; 每个Incident都引用一个DateDimension对象,如下所示:

public class DateDimension : Entity
{
    public virtual int DayOfMonth { get; set; }
    public virtual int Weekday { get; set; }
    public virtual string WeekdayName { get; set; }
    public virtual int Week { get; set; }
    public virtual int MonthPart { get; set; }
    public virtual int Month { get; set; }
    public virtual string MonthName { get; set; }
    public virtual int Quarter { get; set; }
    public virtual int Year { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

DateDimension表已经填充 - 我的系统从未在此处真正创建任何记录.这些是在实际使用之前生成的 - 系统中每个相关日期的一行.这是我系统的功能之一.它承诺每个日期都有一行.如果一个人失踪,那将是一场灾难性的失败.

你可能会问,为什么这样做,如果你是维度建模的新手,就像我两天前写这篇文章一样.

好吧,我每个日期都会有很多事件记录.因此,DateDimension表将比Incident表小很多,并且允许我使用NHibernate LINQ做一些本来很难的事情.例如这样的事情:

        var IncidentsPerWeekday = _incidentRepository
            .GroupBy(i => i.DateDimension.Weekday)
            .Select(g => new Tuple<int,int>(g.Key, g.Count()))
            .ToList();
Run Code Online (Sandbox Code Playgroud)

给我一个小组列表,告诉我这些事件在工作日之间如何划分.当然,这里可以添加许多不同的维度,允许我围绕一堆不同的参数来旋转报表并创建有趣的报表.

然而,有一个小麻烦,在这里我们终于得出了真正的问题.

DateDimension有一个主键,它基本上是它以特定格式表示的日期.对于2011年4月30日,它看起来像这样:

20110430

这是通过在NHibernate中使用自定义IIdentifierGenerator来完成的.由于我们每个日期只有一条记录,因此在我看来这是一个相当干净的方法.

此外,这将是让新事件实体知道对其相关DateDimension的引用的外键的快速方法.有些工厂会知道我们从Incident.RegisterTime DateTime中提取此密钥,然后将其填入DateDimension_id列.

然而,这是我似乎无法找到的方法.Incident.DateDimension正确地要求实体引用.这意味着我必须从数据库加载它(对吗?).在我需要在尽可能短的时间内将大量事件实体插入数据库的某些导入场景中,这可能会太慢.

当然,我可以通过每次插入实体时执行一些自定义SQL并允许NULL引用来为此特定示例执行此操作.这不是理想的,但它可以工作.

但是,有没有办法直接指定DateDimension引用的外键,而不是通过引用真实的存储引用对象来设置它?

那肯定会让我头疼不已!

提前感谢任何见解!

Jam*_*Ide 5

您可以使用ISession.Load方法执行此操作.

myIncident.DateDimension = mySession.Load("20110430");
Run Code Online (Sandbox Code Playgroud)

这将为DateDimension创建一个代理,从而避免数据库访问.顺便提一下,如果您访问代理上的密钥以外的任何属性,它将被加载.