Есть ли "элегантный" способ присвоить определенному свойству значение по умолчанию?
Может быть, DataAnnotations, что-то вроде:
[DefaultValue("true")]
public bool Active { get; set; }
Спасибо.
public bool Inactive { get; set; }
Jes
Есть ли "элегантный" способ присвоить определенному свойству значение по умолчанию?
Может быть, DataAnnotations, что-то вроде:
[DefaultValue("true")]
public bool Active { get; set; }
Спасибо.
public bool Inactive { get; set; }
Jes
Ответы:
Вы можете сделать это, вручную отредактировав код первой миграции:
public override void Up()
{
AddColumn("dbo.Events", "Active", c => c.Boolean(nullable: false, defaultValue: true));
}
Active
для true
при создании Event
объекта , а также. Значение по умолчанию всегда false
указывается в свойстве bool, не допускающем значения NULL, поэтому, если оно не изменено, это структура сущностей будет сохранять в БД. Или я что-то упустил?
Это было какое-то время, но оставляю записку для других. Я добился того, что нужно с помощью атрибута, и я украсил поля моего модельного класса этим атрибутом, как я хочу.
[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) ДобавитьmodelBuilder.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; }
}
}
против
public class Track
{
public Track()
{
LengthInMeters = 400;
}
public int LengthInMeters { get; set; }
}
Это будет работать только для приложений, создающих и потребляющих данные с использованием этого определенного класса. Обычно это не проблема, если код доступа к данным централизован. Чтобы обновить значение во всех приложениях, необходимо настроить источник данных для установки значения по умолчанию. Ответ Деви показывает, как это можно сделать, используя миграцию, 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<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
?
Я признаю, что мой подход избегает всей концепции «Code First». Но если у вас есть возможность просто изменить значение по умолчанию в самой таблице ... это намного проще, чем длины, которые вы должны пройти выше ... Мне просто лень делать всю эту работу!
Кажется, что оригинальная идея постеров сработает:
[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. просто вам нужен конструктор create:
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'.
Я обнаружил, что достаточно просто использовать Auto-Property Initializer для свойства объекта, чтобы выполнить работу.
Например:
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 в течение долгого времени, и я чувствую, что это выстрел в темноте.