[entity-framework] Entity Framework 6 코드 첫 번째 기본값

특정 속성에 기본값을 부여하는 “우아한”방법이 있습니까?

아마도 DataAnnotations에 의해 다음과 같습니다.

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

감사합니다.



답변

코드를 먼저 마이그레이션하여 수동으로 편집하면됩니다.

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


답변

오랜 시간이 지났지 만 다른 사람들에게는 메모를 남깁니다. 속성에 필요한 것을 달성하고 원하는대로 모델 클래스 필드를 해당 속성으로 장식했습니다.

[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 CustomMigrationSqlGenerator());


답변

위의 답변은 실제로 도움이되었지만 솔루션의 일부만 제공했습니다. 가장 큰 문제는 기본값 속성을 제거하자마자 데이터베이스 열의 제약 조건이 제거되지 않는다는 것입니다. 따라서 이전 기본값은 여전히 ​​데이터베이스에 남아 있습니다.

다음은 속성 제거에 대한 SQL 제한 조건 제거를 포함하여 문제점에 대한 완전한 솔루션입니다. 또한 .NET Framework의 기본 DefaultValue특성을 재사용하고 있습니다.

용법

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

이것이 작동하려면 IdentityModels.csConfiguration.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 = $@"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;
    }
}


답변

모델 속성이 ‘자동 속성’일 필요는 없지만 더 쉽습니다. 그리고의 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; }
    }
}

vs.

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

    public int LengthInMeters { get; set; }        
}

이 특정 클래스를 사용하여 데이터를 작성하고 소비하는 응용 프로그램에서만 작동합니다. 데이터 액세스 코드가 중앙 집중화 된 경우 일반적으로 문제가되지 않습니다. 모든 애플리케이션 에서 값을 업데이트하려면 기본값을 설정하도록 데이터 소스를 구성해야합니다. Devi의 답변 은 마이그레이션, SQL 또는 데이터 소스가 사용하는 언어를 사용하여 수행하는 방법을 보여줍니다.


답변

내가 한 일, 엔티티의 생성자에서 값을 초기화했습니다.

참고 : DefaultValue 속성은 속성 값을 자동으로 설정하지 않으므로 직접해야합니다.


답변

@SedatKapanoglu 의견 후에 유창한 API를 사용하면 작동하지 않는 모든 접근 방식을 추가하고 있습니다. 유창한 API를 사용하면 작동하지 않습니다.

1- 사용자 정의 코드 생성기를 작성하고 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);
}


답변

간단 해! 필수로 주석을 달기 만하면됩니다.

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

결과 마이그레이션은 다음과 같습니다.

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

true를 원하면 데이터베이스를 업데이트하기 전에 마이그레이션에서 defaultValue를 true로 변경하십시오.