특정 속성에 기본값을 부여하는 "우아한"방법이 있습니까?
아마도 DataAnnotations에 의해 다음과 같습니다.
[DefaultValue("true")]
public bool Active { get; set; }
감사합니다.
public bool Inactive { get; set; }
😉
특정 속성에 기본값을 부여하는 "우아한"방법이 있습니까?
아마도 DataAnnotations에 의해 다음과 같습니다.
[DefaultValue("true")]
public bool Active { get; set; }
감사합니다.
public bool Inactive { get; set; }
😉
답변:
코드를 먼저 마이그레이션하여 수동으로 편집하면됩니다.
public override void Up()
{
AddColumn("dbo.Events", "Active", c => c.Boolean(nullable: false, defaultValue: true));
}
Active
에 true
만들 때 Event
개체뿐만 아니라. 기본값은 항상 false
nullable이 아닌 bool 속성에 있으므로 변경하지 않으면 엔터티 프레임 워크가 db에 저장하는 것입니다. 아니면 뭔가 빠졌습니까?
오랜 시간이 지났지 만 다른 사람들에게는 메모를 남깁니다. 속성에 필요한 것을 달성하고 원하는대로 모델 클래스 필드를 해당 속성으로 장식했습니다.
[SqlDefaultValue(DefaultValue = "getutcdate()")]
public DateTime CreatedDateUtc { get; set; }
이 두 기사의 도움을 받았습니다.
제가 한:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class SqlDefaultValueAttribute : Attribute
{
public string DefaultValue { get; set; }
}
modelBuilder.Conventions.Add( new AttributeToColumnAnnotationConvention<SqlDefaultValueAttribute, string>("SqlDefaultValue", (p, attributes) => attributes.Single().DefaultValue));
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());
[SqlDefaultValue(DefaultValue = "getutcdate()")]
모든 엔터티 를 착용하지 않고도 전 세계적으로 할 수 있습니다 . 1) 간단히 제거 modelBuilder.Conventions.Add( new AttributeToColumnAnnotationConvention<SqlDefaultValueAttribute, string>("SqlDefaultValue", (p, attributes) => attributes.Single().DefaultValue));
2) 추가modelBuilder.Properties().Where(x => x.PropertyType == typeof(DateTime)).Configure(c => c.HasColumnType("datetime2").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed).HasColumnAnnotation("SqlDefaultValue", "getdate()"));
위의 답변은 실제로 도움이되었지만 솔루션의 일부만 제공했습니다. 가장 큰 문제는 기본값 속성을 제거하자마자 데이터베이스 열의 제약 조건이 제거되지 않는다는 것입니다. 따라서 이전 기본값은 여전히 데이터베이스에 남아 있습니다.
다음은 속성 제거에 대한 SQL 제한 조건 제거를 포함하여 문제점에 대한 완전한 솔루션입니다. 또한 .NET Framework의 기본 DefaultValue
특성을 재사용하고 있습니다.
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
[DefaultValue("getutcdate()")]
public DateTime CreatedOn { get; set; }
이것이 작동하려면 IdentityModels.cs 및 Configuration.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
과 같이 사용자 지정 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;
}
}
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
속성을 설정해야 합니까? 그렇다면 왜 그렇습니까? 내 테스트에서 그것을 떠나는 데 아무런 효과가없는 것 같습니다.
모델 속성이 '자동 속성'일 필요는 없지만 더 쉽습니다. 그리고의 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로 변경하십시오.
true
어떨까요?
본인의 접근 방식이 "코드 우선"개념 전체를 벗어남을 인정합니다. 그러나 테이블 자체의 기본값을 변경할 수있는 능력이 있다면 ... 위에서 수행 해야하는 길이보다 훨씬 간단합니다 ... 나는 모든 작업을 수행하기에는 너무 게으르다!
포스터 독창적 인 아이디어가 작동하는 것처럼 보입니다.
[DefaultValue(true)]
public bool IsAdmin { get; set; }
나는 그들이 단지 따옴표를 추가하는 실수를했다고 생각했지만 ... 아직 직관적이지 않습니다. 다른 제안은 나에게 너무 많았습니다 (테이블에 가서 변경을 수행하는 데 필요한 권한이 있음을 부여했습니다 ... 모든 개발자가 모든 상황에 처할 수는 없습니다). 결국 나는 방금 구식으로했습니다. SQL Server 테이블에서 기본값을 설정했습니다 ... 이미 충분합니다. 참고 : 추가 마이그레이션 및 데이터베이스 업데이트를 수행 한 결과 변경 사항이 적용되었습니다.
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; }
}
}
Products라는 클래스 이름이 있고 IsActive 필드가 있다고 가정합니다. 그냥 생성자가 필요합니다.
Public class Products
{
public Products()
{
IsActive = true;
}
public string Field1 { get; set; }
public string Field2 { get; set; }
public bool IsActive { get; set; }
}
그런 다음 IsActive 기본값은 True입니다!
에디 테 :
SQL 로이 작업을 수행하려면 다음 명령을 사용하십시오.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.IsActive)
.HasDefaultValueSql("true");
}
2016 년 6 월 27 일에 릴리스 된 EF core에서는 유창한 API를 사용하여 기본값을 설정할 수 있습니다. ApplicationDbContext 클래스로 이동하여 메소드 이름 OnModelCreating을 찾거나 작성하고 다음과 같은 유창한 API를 추가하십시오.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<YourTableName>()
.Property(b => b.Active)
.HasDefaultValue(true);
}
.NET Core 3.1에서는 모델 클래스에서 다음을 수행 할 수 있습니다.
public bool? Active { get; set; }
DbContext OnModelCreating에서 기본값을 추가하십시오.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Foundation>()
.Property(b => b.Active)
.HasDefaultValueSql("1");
base.OnModelCreating(modelBuilder);
}
데이터베이스에서 다음 결과
참고 : 속성에 nullable (bool?)이 없으면 다음 경고가 표시됩니다
The 'bool' property 'Active' on entity type 'Foundation' is configured with a database-generated default. This default will always be used for inserts when the property has the value 'false', since this is the CLR default for the 'bool' type. Consider using the nullable 'bool?' type instead so that the default will only be used for inserts when the property value is 'null'.
엔터티 속성에 자동 속성 이니셜 라이저를 사용하는 것만으로도 작업을 완료 할 수 있습니다.
예를 들면 다음과 같습니다.
public class Thing {
public bool IsBigThing{ get; set; } = false;
}
흠 ... 나는 DB를 먼저하고,이 경우 실제로는 훨씬 쉽다. EF6 맞습니까? 모델을 열고 기본값을 설정하려는 열을 마우스 오른쪽 버튼으로 클릭하고 속성을 선택하면 "DefaultValue"필드가 표시됩니다. 그냥 작성하고 저장하십시오. 코드가 설정됩니다.
마일리지는 코드마다 먼저 다를 수 있지만 그와 함께 일하지 않았습니다.
다른 많은 솔루션의 문제점은 모델을 다시 빌드하자마자 처음에는 작동 할 수 있지만 시스템에서 생성 된 파일에 삽입 한 모든 사용자 정의 코드는 버리게된다는 것입니다.
이 방법은 edmx 파일에 추가 속성을 추가하여 작동합니다.
<EntityType Name="Thingy">
<Property Name="Iteration" Type="Int32" Nullable="false" **DefaultValue="1"** />
그리고 필요한 코드를 생성자에 추가하여 :
public Thingy()
{
this.Iteration = 1;
다음과 같이 MSSQL Server 및 클래스 코드 add 속성에서 테이블의 열 기본값을 설정하십시오.
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
같은 속성에 대해.
this.Active = true;
. 가져 오기 할 때 DB 값이 우선하지만, 변경 추적 을 통해 값을 업데이트하려고 할 때 변경 내용을 볼 수 있으므로 새 항목을 가져 와서 가져 오기없이 업데이트를 위해 엔티티를 먼저 첨부하는 경우주의해야한다고 생각합니다 . 오랜 시간 동안 EF를 사용하지 않았기 때문에 코멘트인데, 이것이 어둠 속에서 촬영 된 것 같은 느낌이 듭니다.