Как установить значение по умолчанию для POCO в EF CF?

В подходе Entity Framework Code First, как установить значение по умолчанию для свойства в классе EntityConfiguration POCO?

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime CreatedOn { get; set; }
}

public class PersonConfiguration : EntityConfiguration<Person>
{
    public PersonConfiguration()
    {
        Property(p => p.Id).IsIdentity();
        Property(p => p.Name).HasMaxLength(100);

        //set default value for CreatedOn ?
    }
}

person Andy    schedule 29.06.2010    source источник
comment
Если кому интересно. В итоге я использую «Шаблон репозитория» (stackoverflow .com/questions/3175/), установив значения по умолчанию во время INSERT. Это приятное разделение, так как я думаю о том, чтобы в будущем отказаться от EF.   -  person Andy    schedule 04.04.2013
comment
+1 за отказ от EF в будущем. Впустую потратил много времени, я мог бы просто написать код SQL для моего текущего приложения! Но что вы собираетесь использовать? NHibernate, лучше?   -  person Mzn    schedule 11.03.2014


Ответы (7)


С выпуском Entity Framework 4.3 вы можете сделать это с помощью миграций.

Пошаговое руководство по первой миграции кода EF 4.3

Итак, используя ваш пример, это будет что-то вроде:

public partial class AddPersonClass : DbMigration
{
    public override void Up()
    {
        CreateTable(
            "People",
            c => new
                {
                    Id = c.Int(nullable: false, identity: true),
                    Name = c.String(maxLength: 100),
                    CreatedOn = c.DateTime(nullable: false, defaultValue: DateTime.UtcNow)
                })
            .PrimaryKey(t => t.Id);
    }

    public overide void Down()
    {
        // Commands for when Migration is brought down
    }
}
person Chris Pacey    schedule 24.02.2012
comment
Можно ли использовать AlterColumn для успешного изменения значений по умолчанию без удаления и повторного создания столбца или таблицы? - person Benjamin; 15.06.2012
comment
Есть ли способ сделать это, расширив EntityTypeConfiguration? Например, что-либо с Guid всегда по умолчанию равно newsequentialid()? - person drzaus; 28.08.2012

Вы можете установить значения по умолчанию через конструктор класса. Вот класс, который у меня есть в моем текущем проекте с использованием MVC3 и Entity Framework 4.1:

namespace MyProj.Models
{
using System;
using System.Collections.Generic;

public partial class Task
{
    public Task()
    {
        this.HoursEstimated = 0;
        this.HoursUsed = 0;
        this.Status = "To Start";
    }

    public int ID { get; set; }
    public string Description { get; set; }
    public int AssignedUserID { get; set; }
    public int JobID { get; set; }
    public Nullable<decimal> HoursEstimated { get; set; }
    public Nullable<decimal> HoursUsed { get; set; }
    public Nullable<System.DateTime> DateStart { get; set; }
    public Nullable<System.DateTime> DateDue { get; set; }
    public string Status { get; set; }

    public virtual Job Job { get; set; }
    public virtual User AssignedUser { get; set; }
}
}
person Gavin Coates    schedule 01.06.2011
comment
Что если в базе данных хранится значение HoursUsed 5.0? Будет ли конструктор перезаписывать значение базы данных? Или он сначала создаст, а затем заменит 0 по умолчанию фактическим значением? - person Benjamin; 15.06.2012

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

При создании пользователя я хочу, чтобы некоторые поля устанавливались самим объектом через private setters, например. GUID и дату создания, а не "загрязнять" конструктор.

Мой пользовательский класс:

public class User
{
    public static User Create(Action<User> init)
    {
        var user = new User();
        user.Guid = Guid.NewGuid();
        user.Since = DateTime.Now;
        init(user);
        return user;
    }

    public int UserID { get; set; }

    public virtual ICollection<Role> Roles { get; set; }
    public virtual ICollection<Widget> Widgets { get; set; }

    [StringLength(50), Required]
    public string Name { get; set; }
    [EmailAddress, Required]
    public string Email { get; set; }
    [StringLength(255), Required]
    public string Password { get; set; }
    [StringLength(16), Required]
    public string Salt { get; set; }

    public DateTime Since { get; private set; }
    public Guid Guid { get; private set; }
}

Код вызова:

context.Users.Add(User.Create(c=>
{
    c.Name = "Name";
    c.Email = "[email protected]";
    c.Salt = salt;
    c.Password = "mypass";
    c.Roles = new List<Role> { adminRole, userRole };
}));
person 321X    schedule 30.05.2012

К сожалению, вы не можете. http://social.msdn.microsoft.com/Forums/en/adonetefx/thread/a091ccd6-0ba8-4d4f-8f5e-aafabeb258e4

person Yury Tarabanko    schedule 29.06.2010
comment
Code-first по-прежнему является CTP. Пожалуйста, напишите для этого отчет о подключении, если вы еще этого не сделали. - person Craig Stuntz; 29.06.2010
comment
На самом деле я думаю, что это было активное дизайнерское решение. Установка значений по умолчанию в базе данных является своего рода шагом в сторону от подхода, основанного только на коде. - person Yury Tarabanko; 29.06.2010
comment
Ну, я ожидаю, что только код означает, что все настроено в кодах. Ручная установка значения по умолчанию в db не является хорошей идеей, так как мне нужна структура сущностей для создания базы данных для меня с помощью функции context.CreateDatabase(), и я действительно не хочу поддерживать как коды, так и скрипт db в то же время. - person Andy; 30.06.2010
comment
Вы можете считать значения по умолчанию частью вашего класса Person. Когда вы устанавливаете значения по умолчанию в базе данных, вы столкнетесь со следующей проблемой: эти свойства не будут инициализированы, пока вы не сохраните свою сущность. Это проблема в DB First и Model First, когда вы создали POCO. - person Yury Tarabanko; 30.06.2010
comment
Считаете ли вы хорошей идеей добавление значения по умолчанию при использовании SavingChanges в контексте? - person GibboK; 04.07.2012

Я не уверен, в какой версии EF это станет доступно, но в версии 5 вы наверняка справитесь с этим. Просто установите значение GetDate() по умолчанию для столбца в SQL либо в TSQL, либо в конструкторе, а затем настройте классы EF следующим образом:

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime CreatedOn { get; set; }
}

public class PersonConfiguration : EntityConfiguration<Person>
{
    public PersonConfiguration()
    {
        Property(p => p.Id).IsIdentity();
        Property(p => p.Name).HasMaxLength(100);

        this.Property(p => p.CreatedOn ).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Computed);
    }
}

Обратите внимание, что вам не нужно делать столбец базы данных обнуляемым или свойство POCO.

person S Walsh    schedule 02.04.2013
comment
Я думаю, что смысл в том, чтобы EF устанавливал значение по умолчанию при использовании Code First, и не нужно было входить в SQL и устанавливать их самостоятельно. - person Kyle; 03.04.2013

В случае, когда вы хотите, чтобы SQL Server предоставил дату по умолчанию так, как вы это сделаете, важной частью является defaultValueSql: "GETDATE()", которая установит значение по умолчанию для сервера sql, а не просто оценит время запуска скрипта. (т.е. DateTime.UtcNow)

   public partial class AddPersonClass : DbMigration
    {
    public override void Up()
    {
        CreateTable(
            "People",
            c => new
                {
                    Id = c.Int(nullable: false, identity: true),
                    Name = c.String(maxLength: 100),
                    CreatedOn = c.DateTime(nullable: false, defaultValueSql: "GETDATE()")
                })
            .PrimaryKey(t => t.Id);
    }

    public overide void Down()
    {
        // Commands for when Migration is brought down
    }
}
person user3591722    schedule 22.05.2014

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

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]        
    public DateTime CreatedOn { get; set; }

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

  • PM> Enable-Migrations
  • PM> Add-Migration AlterMyTable Здесь AlterMyTable может быть любое имя. это создаст файл во вновь добавленной папке Migrations в вашем решении currentTimestamp_AlterMyTable.cs - Теперь скопируйте следующее в метод Up currentTimestamp_AlterMyTable.cs
  • AlterColumn("Person", "CreatedOn", n => n.DateTime(nullable: false, defaultValueSql: "SYSUTCDATETIME()")); И после этого выполните последнюю команду в консоли диспетчера программ.
  • PM> Update-Database И теперь, если вы видите таблицу Person в своей базе данных, а затем переходите к столбцу CreatedOn, он должен иметь значение по умолчанию как SYSUTCDATETIME(), то есть теперь, если вы попытаетесь вставить некоторые данные в эту таблицу, ваша база данных автоматически обновит этот столбец CreatedOn для вас. .
person coder89    schedule 24.05.2017