чи є "елегантний" спосіб надати конкретній властивості значення за замовчуванням?
Можливо, завдяки 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
на ненульовому властивості bool, тому, якщо не буде змінено, це те, що рамки сутності збережуть у db. Або я щось пропускаю?
Минув деякий час, але залишав замітку для інших. Я домігся того, що потрібно за допомогою атрибута, і прикрасив свої атрибути класу моделей таким атрибутом, як я хочу.
[SqlDefaultValue(DefaultValue = "getutcdate()")]
public DateTime CreatedDateUtc { get; set; }
Отримав допомогу з цих 2 статей:
Що я зробив:
[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) AddmodelBuilder.Properties().Where(x => x.PropertyType == typeof(DateTime)).Configure(c => c.HasColumnType("datetime2").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed).HasColumnAnnotation("SqlDefaultValue", "getdate()"));
Наведені вище відповіді справді допомогли, але лише доставили частину рішення. Основна проблема полягає в тому, що як тільки ви видалите атрибут значення за замовчуванням, обмеження стовпця в базі даних не буде видалено. Отже попереднє значення за замовчуванням все ще залишатиметься в базі даних.
Ось повне рішення проблеми, включаючи усунення обмежень SQL щодо видалення атрибутів. Я також повторно використовую вбудований DefaultValue
атрибут .NET Framework .
[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; }
}
Це буде працювати лише для програм, що створюють та споживають дані за допомогою цього конкретного класу. Зазвичай це не проблема, якщо код доступу до даних централізований. Для оновлення значення для всіх програм вам потрібно налаштувати джерело даних, щоб встановити значення за замовчуванням. Відповідь Деві показує, як це можна зробити за допомогою міграцій, sql або будь-якої мови, якою розмовляє ваше джерело даних.
Що я зробив, я ініціалізував значення в конструкторі сутності
Примітка: Атрибути DefaultValue не встановлюватимуть значення ваших властивостей автоматично, це потрібно зробити самостійно
Після коментаря @SedatKapanoglu я додаю весь свій підхід, який працює, тому що він мав рацію, просто використовувати вільний 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);
Якщо ви хочете встановити істину, перед оновленням бази даних змініть параметр 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!
Edite :
якщо ви хочете зробити це за допомогою SQL, використовуйте цю команду:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.IsActive)
.HasDefaultValueSql("true");
}
У ядрі EF, випущеному 27 червня 2016 року, ви можете використовувати 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;
}
Хм ... Я роблю БД спочатку, і в цьому випадку це насправді набагато простіше. EF6 так? Просто відкрийте свою модель, клацніть правою кнопкою миші на стовпчику, для якого потрібно встановити за замовчуванням, виберіть властивості, і ви побачите поле "DefaultValue". Просто заповніть це і збережіть. Він встановить код для вас.
Ваш пробіг може залежати спочатку від коду, але я з цим не працював.
Проблема з багатьма іншими рішеннями полягає в тому, що, хоча вони можуть працювати спочатку, як тільки ви відновите модель, вона викине будь-який спеціальний код, який ви вставили у файл, створений машиною.
Цей метод працює, додаючи у файл edmx додаткову властивість:
<EntityType Name="Thingy">
<Property Name="Iteration" Type="Int32" Nullable="false" **DefaultValue="1"** />
І додавши необхідний код до конструктора:
public Thingy()
{
this.Iteration = 1;
Встановіть значення за замовчуванням для стовпця в таблиці на MSSQL Server та в код класу додайте атрибут, наприклад:
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
за те саме майно.
this.Active = true;
? Я думаю, що значення БД буде мати перевагу під час отримання, але обережно, якщо new'ing потім додає сутність для оновлення без вибору спочатку, оскільки відстеження змін може бачити це так, як ви хочете оновити значення. Прокоментуйте, тому що я давно не використовував EF, і мені здається, що це постріл у темряві.