Entity Framework 6 Сначала код Значение по умолчанию

существует ли "элегантный" способ присвоить определенному свойству значение по умолчанию?

Может быть, DataAnnotations, что-то вроде:

[DefaultValue("true")]
public bool Active { get; set; }

Спасибо.

Ответ 1

Вы можете сделать это, вручную изменив первую миграцию кода:

public override void Up()
{    
   AddColumn("dbo.Events", "Active", c => c.Boolean(nullable: false, defaultValue: true));
} 

Ответ 2

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

[SqlDefaultValue(DefaultValue = "getutcdate()")]
public DateTime CreatedDateUtc { get; set; }

Получил помощь из этих двух статей:

Что я сделал:

Определить атрибут

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class SqlDefaultValueAttribute : Attribute
{
    public string DefaultValue { get; set; }
}

В "OnModelCreating" контекста

modelBuilder.Conventions.Add( new AttributeToColumnAnnotationConvention<SqlDefaultValueAttribute, string>("SqlDefaultValue", (p, attributes) => attributes.Single().DefaultValue));

В пользовательском SqlGenerator

private void SetAnnotatedColumn(ColumnModel col)
{
    AnnotationValues values;
    if (col.Annotations.TryGetValue("SqlDefaultValue", out values))
    {
         col.DefaultValueSql = (string)values.NewValue;
    }
}

Затем в конструкторе конфигурации миграции зарегистрируйте собственный генератор SQL.

SetSqlGenerator("System.Data.SqlClient", new HarmonyMigrationSqlGenerator());

Ответ 3

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

Вот полное решение этой проблемы, включая удаление ограничений SQL при удалении атрибутов. Я также повторно использую родной атрибут DefaultValue.NET Framework.

Использование

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

Для этого вам нужно обновить файлы IdentityModels.cs и Configuration.cs

Файл IdentityModels.cs

Добавить/обновить этот метод в классе ApplicationDbContext

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
            base.OnModelCreating(modelBuilder);
            var convention = new AttributeToColumnAnnotationConvention<DefaultValueAttribute, string>("SqlDefaultValue", (p, attributes) => attributes.SingleOrDefault().Value.ToString());
            modelBuilder.Conventions.Add(convention);
}

Файл Configuration.cs

Обновите конструктор класса Configuration, зарегистрировав собственный генератор Sql, например:

internal sealed class Configuration : DbMigrationsConfiguration<ApplicationDbContext>
{
    public Configuration()
    {
        // DefaultValue Sql Generator
        SetSqlGenerator("System.Data.SqlClient", new DefaultValueSqlServerMigrationSqlGenerator());
    }
}

Затем добавьте собственный класс генератора Sql (вы можете добавить его в файл Configuration.cs или отдельный файл)

internal class DefaultValueSqlServerMigrationSqlGenerator : SqlServerMigrationSqlGenerator
{
    private int dropConstraintCount = 0;

    protected override void Generate(AddColumnOperation addColumnOperation)
    {
        SetAnnotatedColumn(addColumnOperation.Column, addColumnOperation.Table);
        base.Generate(addColumnOperation);
    }

    protected override void Generate(AlterColumnOperation alterColumnOperation)
    {
        SetAnnotatedColumn(alterColumnOperation.Column, alterColumnOperation.Table);
        base.Generate(alterColumnOperation);
    }

    protected override void Generate(CreateTableOperation createTableOperation)
    {
        SetAnnotatedColumns(createTableOperation.Columns, createTableOperation.Name);
        base.Generate(createTableOperation);
    }

    protected override void Generate(AlterTableOperation alterTableOperation)
    {
        SetAnnotatedColumns(alterTableOperation.Columns, alterTableOperation.Name);
        base.Generate(alterTableOperation);
    }

    private void SetAnnotatedColumn(ColumnModel column, string tableName)
    {
        AnnotationValues values;
        if (column.Annotations.TryGetValue("SqlDefaultValue", out values))
        {
            if (values.NewValue == null)
            {
                column.DefaultValueSql = null;
                using (var writer = Writer())
                {
                    // Drop Constraint
                    writer.WriteLine(GetSqlDropConstraintQuery(tableName, column.Name));
                    Statement(writer);
                }
            }
            else
            {
                column.DefaultValueSql = (string)values.NewValue;
            }
        }
    }

    private void SetAnnotatedColumns(IEnumerable<ColumnModel> columns, string tableName)
    {
        foreach (var column in columns)
        {
            SetAnnotatedColumn(column, tableName);
        }
    }

    private string GetSqlDropConstraintQuery(string tableName, string columnName)
    {
        var tableNameSplittedByDot = tableName.Split('.');
        var tableSchema = tableNameSplittedByDot[0];
        var tablePureName = tableNameSplittedByDot[1];

        var str = [email protected]"DECLARE @var{dropConstraintCount} nvarchar(128)
SELECT @var{dropConstraintCount} = name
FROM sys.default_constraints
WHERE parent_object_id = object_id(N'{tableSchema}.[{tablePureName}]')
AND col_name(parent_object_id, parent_column_id) = '{columnName}';
IF @var{dropConstraintCount} IS NOT NULL
    EXECUTE('ALTER TABLE {tableSchema}.[{tablePureName}] DROP CONSTRAINT [' + @var{dropConstraintCount} + ']')";

        dropConstraintCount = dropConstraintCount + 1;
        return str;
    }
}

Ответ 4

Свойства вашей модели не обязательно должны быть "авто свойствами". Хотя это проще. А атрибут DefaultValue - это действительно только информативные метаданные Ответ, принятый здесь, является альтернативой конструкторскому подходу.

public class Track
{

    private const int DEFAULT_LENGTH = 400;
    private int _length = DEFAULT_LENGTH;
    [DefaultValue(DEFAULT_LENGTH)]
    public int LengthInMeters {
        get { return _length; }
        set { _length = value; }
    }
}

против.

public class Track
{
    public Track()
    {
        LengthInMeters = 400;   
    }

    public int LengthInMeters { get; set; }        
}

Это будет работать только для приложений, создающих и потребляющих данные с использованием этого конкретного класса. Обычно это не проблема, если код доступа к данным централизован. Чтобы обновить значение для всех приложений, вам необходимо настроить источник данных для установки значения по умолчанию. Ответ Devi показывает, как это можно сделать с помощью миграции, sql или любого другого языка, на котором говорит ваш источник данных.

Ответ 5

Что я сделал, я инициализировал значения в конструкторе объекта

Примечание. Атрибуты DefaultValue не будут автоматически устанавливать значения ваших свойств, вы должны сделать это самостоятельно

Ответ 6

После комментария @SedatKapanoglu я добавляю все свои подходы, которые работают, потому что он был прав, просто использование свободного API не работает.

1- Создать собственный генератор кода и переопределить Generate для ColumnModel.

   public class ExtendedMigrationCodeGenerator : CSharpMigrationCodeGenerator
{

    protected override void Generate(ColumnModel column, IndentedTextWriter writer, bool emitName = false)
    {

        if (column.Annotations.Keys.Contains("Default"))
        {
            var value = Convert.ChangeType(column.Annotations["Default"].NewValue, column.ClrDefaultValue.GetType());
            column.DefaultValue = value;
        }


        base.Generate(column, writer, emitName);
    }

}

2- Назначьте новый генератор кода:

public sealed class Configuration : DbMigrationsConfiguration<Data.Context.EfSqlDbContext>
{
    public Configuration()
    {
        CodeGenerator = new ExtendedMigrationCodeGenerator();
        AutomaticMigrationsEnabled = false;
    }
}

3- Используйте свободный API для создания аннотации:

public static void Configure(DbModelBuilder builder){    
builder.Entity<Company>().Property(c => c.Status).HasColumnAnnotation("Default", 0);            
}

Ответ 7

Я признаю, что мой подход избегает всего подхода "Code First". Но если у вас есть возможность просто изменить значение по умолчанию в самой таблице... это намного проще, чем длины, которые вы должны пройти выше... Я просто слишком ленив, чтобы делать все, что работает!

Похоже, что оригинальная идея плакатов будет работать:

[DefaultValue(true)]
public bool IsAdmin { get; set; }

Я думал, что они просто сделали ошибку, добавив цитаты... но, увы, нет такой интуитивности. Другие предложения были для меня слишком большими (если у меня есть привилегии, необходимые для входа в таблицу и внесения изменений... где не каждый разработчик будет в любой ситуации). В конце концов я просто сделал это старомодным способом. Я установил значение по умолчанию в таблице SQL Server... Я имею в виду, действительно, уже достаточно! ПРИМЕЧАНИЕ. Я также проверил выполнение добавления-миграции и базы данных обновлений и внесенных изменений. введите описание изображения здесь

Ответ 8

Это просто! Просто комментируйте с необходимыми.

[Required]
public bool MyField { get; set; }

результирующая миграция будет:

migrationBuilder.AddColumn<bool>(
name: "MyField",
table: "MyTable",
nullable: false,
defaultValue: false);

Если вы хотите true, измените defaultValue на true в миграции перед обновлением базы данных

Ответ 9

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

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Aim.Data.Domain
{
    [MetadataType(typeof(LoginModel))]
    public partial class Login
    {       
        public Login(bool status)
        {
            this.CreatedDate = DateTime.Now;
            this.ModifiedDate = DateTime.Now;
            this.Culture = "EN-US";
            this.IsDefaultPassword = status;
            this.IsActive = status;
            this.LoginLogs = new HashSet<LoginLog>();
            this.LoginLogHistories = new HashSet<LoginLogHistory>();
        }


    }

    public class LoginModel
    {

        [Key]
        [ScaffoldColumn(false)] 
        public int Id { get; set; }
        [Required]
        public string LoginCode { get; set; }
        [Required]
        public string Password { get; set; }
        public string LastPassword { get; set; }     
        public int UserGroupId { get; set; }
        public int FalseAttempt { get; set; }
        public bool IsLocked { get; set; }
        public int CreatedBy { get; set; }       
        public System.DateTime CreatedDate { get; set; }
        public Nullable<int> ModifiedBy { get; set; }      
        public Nullable<System.DateTime> ModifiedDate { get; set; }       
        public string Culture { get; set; }        
        public virtual ICollection<LoginLog> LoginLogs { get; set; }
        public virtual ICollection<LoginLogHistory> LoginLogHistories { get; set; }
    }

}

Ответ 10

Моим решением было установить "GenerateSmartDefaults = True" в качестве параметра для SqlPackage.exe.

/p:GenerateSmartDefaults=True

Насколько я знаю, вы можете сделать это двумя способами:

  • Развертывание с использованием профиля публикации с установленным значением true, если у вас есть Visual Studio "Проект базы данных SQL".
  • Передайте аргумент (см. Фрагмент кода выше) в SqlPackage.exe

Sqlpackage.exe используется Visual Studio при публикации "Проект базы данных SQL" (я думаю), а также (определенно) "Dacpactask SQL Azure" -task в конвейере Azure DevOps.

Это было одно из нескольких предложений здесь: https://www.mssqltips.com/sqlservertip/5456/using-advanced-publish-settings-for-visual-studio-database-project/

Примечание. Если у вас нет визуальной студии "Проект базы данных SQL", вы сначала делаете код и хотите управлять исходным кодом своей базы данных SQL, а также автоматически развертывать базу данных, вы можете использовать эту концепцию: https://www.sswug.org/bentaylor/редакционных/базы данных-проекты-против-лица-рамочные-базы-данных миграции /

Ответ 11

Предположим, у вас есть имя класса с именем Products и поле IsActive. просто вам нужен конструктор create:

Public class Products
{
    public Products()
    {
       IsActive = true;
    }
 public string Field1 { get; set; }
 public string Field2 { get; set; }
 public bool IsActive { get; set; }
}

Тогда ваше значение по умолчанию IsActive - True!

Edite:

если вы хотите сделать это с SQL, используйте эту команду:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .Property(b => b.IsActive)
        .HasDefaultValueSql("true");
}

Ответ 12

Я обнаружил, что достаточно использовать Auto-Property Initializer для свойства entity, чтобы выполнить задание.

Например:

public class Thing {
    public bool IsBigThing{ get; set; } = false;
}

Ответ 13

Хм... Сначала я делаю DB, и в этом случае это намного проще. EF6 правильно? Просто откройте свою модель, щелкните правой кнопкой мыши на столбце, для которого вы хотите установить значение по умолчанию, выберите свойства, и вы увидите поле "DefaultValue". Просто заполните это и сохраните. Он настроит для вас код.

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

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

Этот метод работает, добавляя дополнительное свойство в файл edmx:

<EntityType Name="Thingy">
  <Property Name="Iteration" Type="Int32" Nullable="false" **DefaultValue="1"** />

И добавив необходимый код в конструктор:

public Thingy()
{
  this.Iteration = 1;

Ответ 14

Задайте значение по умолчанию для столбца в таблице на сервере MSSQL и в атрибуте добавления кода класса, например:

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]

для того же свойства.