существует ли "элегантный" способ присвоить определенному свойству значение по умолчанию?
Может быть, DataAnnotations, что-то вроде:
[DefaultValue("true")]
public bool Active { get; set; }
Спасибо.
существует ли "элегантный" способ присвоить определенному свойству значение по умолчанию?
Может быть, 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; }
}
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 HarmonyMigrationSqlGenerator());
Вышеупомянутые ответы действительно помогли, но только доставили часть решения. Основная проблема заключается в том, что как только вы удалите атрибут значения по умолчанию, ограничение на столбец в базе данных не будет удалено. Поэтому предыдущее значение по умолчанию все равно останется в базе данных.
Вот полное решение этой проблемы, включая удаление ограничений 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 = [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; }
}
Это будет работать только для приложений, создающих и потребляющих данные с использованием этого конкретного класса. Обычно это не проблема, если код доступа к данным централизован. Чтобы обновить значение для всех приложений, вам необходимо настроить источник данных для установки значения по умолчанию. Ответ 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<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);
}
Я признаю, что мой подход избегает всего подхода "Code First". Но если у вас есть возможность просто изменить значение по умолчанию в самой таблице... это намного проще, чем длины, которые вы должны пройти выше... Я просто слишком ленив, чтобы делать все, что работает!
Похоже, что оригинальная идея плакатов будет работать:
[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 в миграции перед обновлением базы данных
Просто перегрузите конструктор по умолчанию класса 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; }
}
}
Моим решением было установить "GenerateSmartDefaults = True" в качестве параметра для SqlPackage.exe.
/p:GenerateSmartDefaults=True
Насколько я знаю, вы можете сделать это двумя способами:
Sqlpackage.exe используется Visual Studio при публикации "Проект базы данных SQL" (я думаю), а также (определенно) "Dacpactask SQL Azure" -task в конвейере Azure DevOps.
Это было одно из нескольких предложений здесь: https://www.mssqltips.com/sqlservertip/5456/using-advanced-publish-settings-for-visual-studio-database-project/
Примечание. Если у вас нет визуальной студии "Проект базы данных SQL", вы сначала делаете код и хотите управлять исходным кодом своей базы данных SQL, а также автоматически развертывать базу данных, вы можете использовать эту концепцию: https://www.sswug.org/bentaylor/редакционных/базы данных-проекты-против-лица-рамочные-базы-данных миграции /
Предположим, у вас есть имя класса с именем 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");
}
Я обнаружил, что достаточно использовать Auto-Property Initializer для свойства entity, чтобы выполнить задание.
Например:
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 и в атрибуте добавления кода класса, например:
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
для того же свойства.