4

Я знаю, что об этом много, и я прочитал большинство из них. Однако для меня несколько вещей остаются неясными и до сих пор не работают.Свободное сопоставление NHibernate для DateTime со значением по умолчанию

Если у меня есть на моей схеме базы данных поле типа DateTime, и я хотел бы присвоить ему значение по умолчанию, я бы сделать что-то вроде этого:

create table [mySchema].[MyTable](
    ObjectGuid uniqueidentifier CONSTRAINT Id PRIMARY KEY, 
    SomeTextToStore nvarchar(128) NULL, 
    CDate datetime NOT NULL DEFAULT GETDATE(), 
    CUser nvarchar(64) DEFAULT CURRENT_USER 
); 
GO 

(Не знаю, если это важно: Я использую SQL Server Express 2014. Свободная конфигурация для SQL Server 2012.)

Это отлично работает при выполнении INSERT с ISQL, вставляет временную метку момента добавления записи.

Использование свободно я хотел бы написать что-то вроде этого:

домена:

public class MyObject 
{ 
    public virtual Guid Id {get; set} 
    public virtual string SomeTextToStore {get; set;} 
    public virtual DateTime? CDate {get; set;} 
    public virtual string CUser {get; set;} 
} 

ПРИМЕЧАНИЕ: Я сделал CDate обнуляемым!

А класс отображения так:

class MyObjectMap : ClassMap<MyObject> 
{ 
    public MyObjectMap() 
    { 
     Table("MySchema.MyTable"); 
     Id(x => x.Id).GeneratedBy.GuidComb(); 
     Map(x => x.SomeTextToStore).Length(128).Nullable(); 
     Map(x => x.CDate).Not.Nullable().Default("getdate()"); 
     Map(x => x.CUser).Not.Nullable().Default("CURRENT_USER); 
    } 
} 

В программе (в моем случае это библиотека, которая может быть вызвана из нескольких типов программ) я сделать что-то вроде:

public void EnterSomeText() 
{ 
    using (var session = sessionManager.OpenSession()) 
    { 
     using (var transaction = session.BeginTransaction()) 
     { 
      var myObj = new MyObject(); 
      myObj.SomeTextToStore("bla bla bla"); 
      session.SaveOrUpdate(myObj); 
      transaction.Commit(); 
     } 
     session.Close(); 
    } 
} 

Это всегда заканчивается Исключение переполнения DateTime! (Переполнение SqlDateTime должно быть между 1/1/1753 12:00:00 и 12/31/9999 23:59:59 PM)

Похоже, что не передается значение CDate вызывает проблему , Когда я добавляю по умолчанию в моей библиотеке, как например это работает:

... 
myObj.SomeTextToStore("bla bla bla"); 
myObj.CDate = DateTime.Now; // <---- Set the date here 
session.SaveOrUpdate(myObj); 
... 

Но это на самом деле не решение ....

Вопросы:

  1. Что же я делать неправильно/отсутствует?
  2. Какова правильная стратегия, когда определяет значения по умолчанию? Делать это в базе данных или просто в коде? (Когда начинают простой новый проект ванили, я предпочел бы делать все от C# код, даже создавать, а затем обновить схему ...)
  3. Что касается доменных классов: Разумно создать конструктор, , заполняющие поля с настройками по умолчанию?

Я делаю это для поля CUser, потому что в CUser Я хотел бы добавить текущий пользовательский контекст

public MyObject() 
{ 
    var o = System.Security.Principal.WindowsIdentity.GetCurrent(); 
    if (o != null) 
    { 
     CUser = o.Name; 
    } 
} 

Вместо того, чтобы заполнить поле CDate с текущей датой в моей библиотеке слоя DB-доступа I Could сделайте это также в конструкторе домена-класса, такого как:

public MyObject() 
{ 
    var o = System.Security.Principal.WindowsIdentity.GetCurrent(); 
    if (o != null) 
    { 
     CUser = o.Name; 
    } 
    CDate = DateTime.Now; 
} 

Большое спасибо за вашу помощь и комментарии!

+0

Вы прочитали этот [пост] (/ a/35700837/1178314) о значениях по умолчанию? Определение значений по умолчанию при сопоставлении почти только для генерации dml (создание ограничения по умолчанию в db), а не для определения значений по умолчанию для ваших вновь созданных объектов. Это должно быть сделано через инициализаторы конструктора или полей, как и для любого класса. –

+0

+1 @ Frédéric. Это уточняет вопрос о конструкторе. Для этого требуется написать частный метод Init() и вызвать его из конструктора, так как не нужно присваивать значения виртуальным реквизитам в конструкторе .... – ThommyB

ответ

3

Обычно для этого типа отображения я следующий в моем отображении:

DynamicInsert(); 
DynamicUpdate(); 

Таким образом, если у вас есть обнуляемые типы в C# и вы не установили их к чему-либо NHibernate не будет включать их в вставить или обновить. Мне никогда не нравится, когда nhibernate обновляет столбцы, которые в любом случае не изменялись в коде.

Кроме того, при указании .Not.Nullable(); и .Default("getdate()") в картографии все это используется для генерации схемы. На самом деле он не используется nhibernate для выполнения какой-либо проверки или дефолта. Это осталось до базы данных.

+0

спасибо за это. , но иногда мне нужно обновить значения до пустых. , и я havent смог получить .Default (defaultValue), работающий в любом случае - единственное, что установлено в базе данных MsSql. или просто включить значение по умолчанию в объект –

0

Вы определили этот столбец как NOT NULL в базе данных и Nullable() в картографии. FluentNHibernate отправляет DbNull в базу данных, которая получает отклонение, так как столбец базы данных не имеет значения NULL.

Вы должны решить, где находится ваша логика. Это ваш код или база данных, кто является мастером?

Установка значения по умолчанию в FlientNHibernate обсуждалась, например, в this question.

Предложенное код оттуда:

Map(x => x.SubmitionDate).Default("getdate()").Not.Nullable(); 

В общем, я всегда советую использовать NHibernate Profiler (платный инструмент), чтобы увидеть, что запросы идут в базу данных, и почему они терпят неудачу. Бесценный для оптимизации, вы используете ORM, будьте осторожны!

+0

Спасибо, 'Nullable()' это опечатка, мне пришлось стричь немного по сравнению с моим кодом, на самом деле это немного сложнее. – ThommyB

+0

И спасибо за подсказку о NHibernate Profiler. Я посмотрю на это ... – ThommyB