Programming

Entity Framework 6 코드 첫 번째 기본값

procodes 2020. 5. 16. 22:52
반응형

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 HarmonyMigrationSqlGenerator());

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

다음은 속성 제거에 대한 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);            
}

본인의 접근 방식이 전체 "코드 우선"접근 방식을 벗어나는 것을 인정합니다. 그러나 테이블 자체의 기본값을 변경할 수있는 능력이 있다면 ... 위에서 수행 해야하는 길이보다 훨씬 간단합니다 ... 나는 모든 작업을 수행하기에는 너무 게으르다!

포스터 독창적 인 아이디어가 효과가있는 것처럼 보입니다.

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

나는 그들이 단지 따옴표를 추가하는 실수를했다고 생각했지만 ... 아직 직관적이지 않습니다. 다른 제안은 나에게 너무 많았습니다 (테이블에 가서 변경을 수행하는 데 필요한 권한이 있음을 부여했습니다 ... 모든 상황에서 개발자가 많지 않은 곳). 결국 나는 방금 구식으로했습니다. SQL Server 테이블에서 기본값을 설정했습니다. 이미 충분합니다. 참고 : 추가 마이그레이션 및 데이터베이스 업데이트를 수행 한 결과 변경 사항이 적용되었습니다. 여기에 이미지 설명을 입력하십시오


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

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

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

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

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


Just Overload the default constructor of Model class and pass any relevant parameter which you may or may not use. By this you can easily supply default values for attributes. Below is an example.

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

}

Lets consider you have a class name named Products and you have a IsActive field. just you need a create constructor :

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

Then your IsActive default value is True!

Edite :

if you want to do this with SQL use this command :

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

I found that just using Auto-Property Initializer on entity property is enough to get the job done.

For example:

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

Hmm... I do DB first, and in that case, this is actually a lot easier. EF6 right? Just open your model, right click on the column you want to set a default for, choose properties, and you will see a "DefaultValue" field. Just fill that out and save. It will set up the code for you.

마일리지는 코드마다 먼저 다를 수 있지만 그와 함께 일하지 않았습니다.

다른 많은 솔루션의 문제점은 모델을 다시 빌드하자마자 처음에는 작동하지만 시스템 생성 파일에 삽입 한 사용자 정의 코드는 버리게된다는 것입니다.

이 방법은 edmx 파일에 추가 속성을 추가하여 작동합니다.

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

그리고 필요한 코드를 생성자에 추가하여 :

public Thingy()
{
  this.Iteration = 1;

다음과 같이 MSSQL Server 및 클래스 코드 add 속성에서 테이블의 열 기본값을 설정하십시오.

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]

같은 속성에 대해.

참고 URL : https://stackoverflow.com/questions/19554050/entity-framework-6-code-first-default-value

반응형