Entity Framework 6 Сначала код Значение по умолчанию
есть ли «элегантный» способ присвоить определенному свойству значение по умолчанию?
Может быть, DataAnnotations, что-то вроде:
[DefaultValue("true")] public bool Active { get; set; }
Спасибо.
- Перенос EF для изменения типа данных столбцов
- Как сопоставить наследование типа таблицы на тип (TPT) в дизайнере Entity?
- Установка значения по умолчанию для свойства DateTime в DateTime.Now внутри значения System.ComponentModel Default Attrbute
- свойство навигации должно быть виртуальным - не требуется в ef core?
- Метод DbSet.Find смехотворно медленный по сравнению с .SingleOrDefault для ID
- Как передать параметры методу DbContext.Database.ExecuteSqlCommand?
- Добавление подсказки при вызове функции с табличными значениями
- Entity Framework слишком медленная. Какие у меня варианты?
- Считаете ли вы целесообразным перейти на Entity Framework?
- Ключевое слово не поддерживается: 'server'
- Entity Framework 4 выборочно ленивые свойства загрузки
- Зависимость впрыска в единицу работы с использованием репозиториев
- Entity framework 4.3 запускает миграцию при запуске приложения
Вы можете сделать это, вручную изменив первую миграцию кода:
public override void Up() { AddColumn("dbo.Events", "Active", c => c.Boolean(nullable: false, defaultValue: true)); }
Это было какое-то время, но оставив записку для других. Я достиг того, что нужно с атрибутом, и я украсил поля classа модели этим атрибутом, как я хочу.
[SqlDefaultValue(DefaultValue = "getutcdate()")] public DateTime CreatedDateUtc { get; set; }
Получил помощь из этих двух статей:
- EF на CodePlex
- Блог Энди Мехалика
Что я сделал:
Определить атрибут
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] public class SqlDefaultValueAttribute : Attribute { public string DefaultValue { get; set; } }
В «OnModelCreating» контекста
modelBuilder.Conventions.Add( new AttributeToColumnAnnotationConvention("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 при удалении атрибутов. Я также повторно использую собственный атрибут DefaultValue
.NET Framework.
Применение
[DatabaseGenerated(DatabaseGeneratedOption.Computed)] [DefaultValue("getutcdate()")] public DateTime CreatedOn { get; set; }
Для этого вам необходимо обновить файлы IdentityModels.cs и Configuration.cs
Файл IdentityModels.cs
Добавить / обновить этот метод в classе ApplicationDbContext
protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); var convention = new AttributeToColumnAnnotationConvention("SqlDefaultValue", (p, attributes) => attributes.SingleOrDefault().Value.ToString()); modelBuilder.Conventions.Add(convention); }
Файл Configuration.cs
Обновите конструктор classа Configuration
, зарегистрировав собственный генератор Sql, например:
internal sealed class Configuration : DbMigrationsConfiguration { public Configuration() { // DefaultValue Sql Generator SetSqlGenerator("System.Data.SqlClient", new DefaultValueSqlServerMigrationSqlGenerator()); } }
Затем добавьте собственный class генератора 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 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; } }
Свойства вашей модели не обязательно должны быть «авто свойствами». Хотя это проще. А атрибут 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; } }
Это будет работать только для приложений, создающих и потребляющих данные с использованием этого конкретного classа. Обычно это не проблема, если код доступа к данным централизован. Чтобы обновить значение для всех приложений, вам необходимо настроить источник данных для установки значения по умолчанию. Ответ Devi показывает, как это можно сделать с помощью миграции, sql или любого другого языка, на котором говорит ваш источник данных.
Что я сделал, я инициализировал значения в конструкторе объекта
Примечание: атрибуты DefaultValue не будут автоматически устанавливать значения ваших свойств, вы должны сделать это самостоятельно
После комментария @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 { public Configuration() { CodeGenerator = new ExtendedMigrationCodeGenerator(); AutomaticMigrationsEnabled = false; } }
3- Используйте беглый api для создания annotations:
public static void Configure(DbModelBuilder builder){ builder.Entity().Property(c => c.Status).HasColumnAnnotation("Default", 0); }
Просто перегрузите конструктор по умолчанию classа 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(); this.LoginLogHistories = new HashSet(); } } 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 ModifiedBy { get; set; } public Nullable ModifiedDate { get; set; } public string Culture { get; set; } public virtual ICollection LoginLogs { get; set; } public virtual ICollection LoginLogHistories { get; set; } } }
Я не знаю, откуда берутся ответы!
Давайте рассмотрим, что у вас есть имя classа под названием 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() .Property(b => b.IsActive) .HasDefaultValueSql("true"); }
Я признаю, что мой подход избегает всего подхода «Code First». Но если у вас есть возможность просто изменить значение по умолчанию в самой таблице … это намного проще, чем длины, которые вы должны пройти выше … Я просто слишком ленив, чтобы делать все это!
Похоже, что оригинальная идея плакатов будет работать:
[DefaultValue(true)] public bool IsAdmin { get; set; }
Я думал, что они просто допустили ошибку, добавив цитаты … но, увы, нет такой интуитивности. Другие предложения были для меня слишком большими (если у меня есть привилегии, необходимые для входа в таблицу и внесения изменений … где не каждый разработчик будет в любой ситуации). В конце концов я просто сделал это старомодным способом. Я установил значение по умолчанию в таблице SQL Server … Я имею в виду, действительно, уже достаточно! ПРИМЕЧАНИЕ. Я также тестировал выполнение добавления-миграции и базы данных обновлений и изменений.
Я обнаружил, что достаточно использовать Auto-Property Initializer для свойства entity, чтобы выполнить работу.
Например:
public class Thing { public bool IsBigThing{ get; set; } = false; }
Хм … Сначала я делаю БД, и в этом случае это на самом деле намного проще. EF6 правильно? Просто откройте свою модель, щелкните правой кнопкой мыши на столбце, для которого вы хотите установить значение по умолчанию, выберите свойства, и вы увидите поле «DefaultValue». Просто заполните это и сохраните. Он настроит код для вас.
Ваш пробег может отличаться от кода, хотя я не работал с этим.
Проблема с множеством других решений заключается в том, что, хотя они могут работать на начальном этапе, как только вы перестраиваете модель, она выкинет любой пользовательский код, который вы вставляете в машинный файл.
Этот метод работает, добавляя дополнительное свойство в файл edmx:
И добавив необходимый код к конструктору:
public Thingy() { this.Iteration = 1;
Задайте значение по умолчанию для столбца в таблице на сервере MSSQL и в атрибуте добавления кода classа, например:
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
для того же свойства.