Можно ли установить внешний ключ ссылки непосредственно в NHibernate? - PullRequest
2 голосов
/ 23 января 2011

Получил проект, который собирает данные в виде файлов XML из конкретной системы (они поступают в виде веб-запросов), преобразует их в модель сущностей и помещает их в базу данных для составления отчетов.

В проекте используется следующее программное обеспечение (относящееся к этому вопросу):

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

, и это отображаетсятаким образом:

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

(Идентификатор исходит из базового класса Entity)

Поскольку те, кто имеет дело с такими вещами, вероятно, уже читали из кода, я пытаюсь выполнить некоторое измерение размеровВот.Я новичок в этой теме, и, по всей вероятности, Doing It Wrong (tm), но я надеюсь, по крайней мере, получить некоторые преимущества от этого способа сделать это;Каждый инцидент ссылается на объект 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; }
}

Таблица DateDimension уже заполнена - моя система никогда не создает здесь никаких записей.Они создаются задолго до фактического использования - одна строка для каждой соответствующей даты в системе.Это одна из особенностей моей системы.Это обещает, что одна строка будет там для каждой возможной даты.Если кто-то пропустил, это было бы катастрофическим отказом.

Почему, спросите вы, если вы новичок в многомерном моделировании, как я это делал два дня назад, когда писал это.

Ну, у меня будет много записей об инцидентах на каждую дату.Таким образом, таблица DateDimension будет намного меньше, чем таблица Incident, и позволит мне делать вещи с NHibernate LINQ, которые в противном случае были бы трудными.Например, что-то вроде этого:

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

Предоставляя мне список групп, рассказывающих мне, как инциденты распределяются между рабочими днями.Есть, конечно, много разных измерений, которые можно добавить сюда, что позволяет мне сводить отчеты по куче различных параметров и создавать интересные отчеты.

Однако есть одно небольшое неудобство, и здесь мы, наконец, приходим креальный вопрос.

DateDimension имеет первичный ключ, который в основном представляет собой дату, которую он представляет в определенном формате.Для 30 апреля 2011 года это будет выглядеть так:

20110430

Это делается с помощью пользовательского IIdentifierGenerator в NHibernate.Поскольку на каждую дату у нас будет только одна запись, на мой взгляд, это достаточно чистый способ сделать это.

Кроме того, это был бы быстрый способ сообщить новым сущностям Инцидента о внешнем ключессылка на их соответствующий DateDimension.Некоторые фабрики могут знать, что мы извлекаем этот ключ, скажем, из Incident.RegisterTime DateTime, а затем помещаем его в столбец DateDimension_id.

Однако я не могу найти способ сделать это.Incident.DateDimension по праву требует ссылки на сущность.Что означает, что я должен загрузить его из базы данных (верно?).Что может быть слишком медленным в определенных сценариях импорта, где мне нужно вставить МНОЖЕСТВО сущностей Инцидентов в базу данных в кратчайшие сроки.

Конечно, я мог бы сделать это для этого конкретного примера, выполнив некоторыеПользовательский SQL каждый раз, когда я вставляю сущность и допускаю пустые ссылки.Это не идеально, но это может сработать.

Однако есть ли способ указать внешний ключ ссылки DateDimension напрямую, вместо того, чтобы устанавливать его со ссылкой на реальный, сохраненный ссылочный объект?

Это, конечно, избавило бы меня от огромной головной боли!

Заранее спасибо за понимание!

Ответы [ 2 ]

5 голосов
/ 23 января 2011

Вы можете сделать это, используя метод ISession.Load.

myIncident.DateDimension = mySession.Load("20110430");

Это создаст прокси для DateDimension, что позволит избежать отключения базы данных. Кстати, если вы получите доступ к каким-либо свойствам, кроме ключа прокси-сервера, он будет загружен.

1 голос
/ 23 января 2011

Не на 100% положительно, что это будет работать, но вы можете попытаться установить ссылку на новый экземпляр класса DateDimension с соответствующим Id. Это предполагает, что между Incident и DateDimension нет никакого каскадирования, что, как я полагаю, является правильным предположением, поскольку DateDimensions, вероятно, неизменны в вашей модели данных.

В качестве альтернативы вы можете выставить столбец FK в вашем отображении и установить его непосредственно.

...