Gibt es eine "elegante" Möglichkeit, einer bestimmten Eigenschaft einen Standardwert zu geben?
Vielleicht von DataAnnotations, so etwas wie:
[DefaultValue("true")]
public bool Active { get; set; }
Danke dir.
public bool Inactive { get; set; }😉
Gibt es eine "elegante" Möglichkeit, einer bestimmten Eigenschaft einen Standardwert zu geben?
Vielleicht von DataAnnotations, so etwas wie:
[DefaultValue("true")]
public bool Active { get; set; }
Danke dir.
public bool Inactive { get; set; }😉
Antworten:
Sie können dies tun, indem Sie die erste Migration des Codes manuell bearbeiten:
public override void Up()
{
AddColumn("dbo.Events", "Active", c => c.Boolean(nullable: false, defaultValue: true));
}
Activeauf , truewenn eine der Erstellung Eventals auch Objekt. Der Standardwert befindet sich immer in falseeiner nicht nullbaren Bool-Eigenschaft. Sofern nicht geändert, wird das Entity-Framework in der Datenbank gespeichert. Oder fehlt mir etwas?
Es ist eine Weile her, aber eine Notiz für andere hinterlassen. Ich habe mit einem Attribut erreicht, was benötigt wird, und meine Modellklassenfelder mit diesem Attribut nach Belieben dekoriert.
[SqlDefaultValue(DefaultValue = "getutcdate()")]
public DateTime CreatedDateUtc { get; set; }
Habe die Hilfe dieser 2 Artikel bekommen:
Was ich getan habe:
[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;
}
}
Registrieren Sie dann im Konstruktor für die Migrationskonfiguration den benutzerdefinierten SQL-Generator.
SetSqlGenerator("System.Data.SqlClient", new CustomMigrationSqlGenerator());
[SqlDefaultValue(DefaultValue = "getutcdate()")]jede Entität anzulegen. 1) Einfach entfernen modelBuilder.Conventions.Add( new AttributeToColumnAnnotationConvention<SqlDefaultValueAttribute, string>("SqlDefaultValue", (p, attributes) => attributes.Single().DefaultValue)); 2) HinzufügenmodelBuilder.Properties().Where(x => x.PropertyType == typeof(DateTime)).Configure(c => c.HasColumnType("datetime2").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed).HasColumnAnnotation("SqlDefaultValue", "getdate()"));
Die obigen Antworten haben wirklich geholfen, aber nur einen Teil der Lösung geliefert. Das Hauptproblem besteht darin, dass die Einschränkung für die Spalte in der Datenbank nicht entfernt wird, sobald Sie das Standardwertattribut entfernen. Der vorherige Standardwert bleibt also weiterhin in der Datenbank.
Hier finden Sie eine vollständige Lösung des Problems, einschließlich des Entfernens von SQL-Einschränkungen beim Entfernen von Attributen. Ich verwende auch das native DefaultValueAttribut von .NET Framework erneut .
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
[DefaultValue("getutcdate()")]
public DateTime CreatedOn { get; set; }
Damit dies funktioniert, müssen Sie die Dateien IdentityModels.cs und Configuration.cs aktualisieren
Fügen Sie diese Methode in Ihrer ApplicationDbContextKlasse hinzu / aktualisieren Sie sie
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);
}
Aktualisieren Sie Ihren ConfigurationKlassenkonstruktor, indem Sie einen benutzerdefinierten SQL-Generator wie folgt registrieren:
internal sealed class Configuration : DbMigrationsConfiguration<ApplicationDbContext>
{
public Configuration()
{
// DefaultValue Sql Generator
SetSqlGenerator("System.Data.SqlClient", new DefaultValueSqlServerMigrationSqlGenerator());
}
}
Fügen Sie als Nächstes eine benutzerdefinierte SQL-Generatorklasse hinzu (Sie können sie der Datei Configuration.cs oder einer separaten Datei hinzufügen ).
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)]Attribut festlegen ? Wenn ja warum? In meinen Tests schien es keine Wirkung zu haben, es wegzulassen.
Ihre Modelleigenschaften müssen keine "automatischen Eigenschaften" sein, auch wenn dies einfacher ist. Und das DefaultValue-Attribut besteht eigentlich nur aus informativen Metadaten. Die hier akzeptierte Antwort ist eine Alternative zum Konstruktoransatz.
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; }
}
Dies funktioniert nur für Anwendungen, die Daten mit dieser bestimmten Klasse erstellen und verarbeiten. Normalerweise ist dies kein Problem, wenn der Datenzugriffscode zentralisiert ist. Um den Wert für alle Anwendungen zu aktualisieren , müssen Sie die Datenquelle so konfigurieren, dass ein Standardwert festgelegt wird. Die Antwort von Devi zeigt, wie dies mithilfe von Migrationen, SQL oder einer anderen Sprache, die Ihre Datenquelle spricht, durchgeführt werden kann.
Was ich getan habe, habe ich Werte im Konstruktor der Entität initialisiert
Hinweis: DefaultValue-Attribute legen die Werte Ihrer Eigenschaften nicht automatisch fest, sondern müssen selbst ausgeführt werden
Nach dem Kommentar von @SedatKapanoglu füge ich meinen gesamten Ansatz hinzu, der funktioniert, da er Recht hatte. Nur die Verwendung der fließenden API funktioniert nicht.
1- Erstellen Sie einen benutzerdefinierten Codegenerator und überschreiben Sie Generieren für ein 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- Weisen Sie den neuen Codegenerator zu:
public sealed class Configuration : DbMigrationsConfiguration<Data.Context.EfSqlDbContext>
{
public Configuration()
{
CodeGenerator = new ExtendedMigrationCodeGenerator();
AutomaticMigrationsEnabled = false;
}
}
3- Verwenden Sie eine fließende API, um die Anmerkung zu erstellen:
public static void Configure(DbModelBuilder builder){
builder.Entity<Company>().Property(c => c.Status).HasColumnAnnotation("Default", 0);
}
Es ist einfach! Einfach mit erforderlich kommentieren.
[Required]
public bool MyField { get; set; }
Die resultierende Migration wird sein:
migrationBuilder.AddColumn<bool>(
name: "MyField",
table: "MyTable",
nullable: false,
defaultValue: false);
Wenn Sie true möchten, ändern Sie den Standardwert bei der Migration in true, bevor Sie die Datenbank aktualisieren
true?
Ich gebe zu, dass mein Ansatz dem gesamten "Code First" -Konzept entgeht. Aber wenn Sie die Möglichkeit haben, nur den Standardwert in der Tabelle selbst zu ändern ... ist es viel einfacher als die Längen, die Sie oben durchlaufen müssen ... Ich bin einfach zu faul, um all diese Arbeit zu erledigen!
Es scheint fast so, als würde die ursprüngliche Idee des Plakats funktionieren:
[DefaultValue(true)]
public bool IsAdmin { get; set; }
Ich dachte, sie hätten nur den Fehler gemacht, Zitate hinzuzufügen ... aber leider keine solche Intuitivität. Die anderen Vorschläge waren einfach zu viel für mich (vorausgesetzt, ich habe die erforderlichen Berechtigungen, um in die Tabelle zu gehen und die Änderungen vorzunehmen ... wo nicht jeder Entwickler in jeder Situation wird). Am Ende habe ich es einfach auf die altmodische Weise gemacht. Ich habe den Standardwert in der SQL Server-Tabelle festgelegt ... ich meine wirklich schon genug! HINWEIS: Ich habe die Durchführung einer Add-Migration- und Update-Datenbank weiter getestet und die Änderungen stecken geblieben.

Überladen Sie einfach den Standardkonstruktor der Modellklasse und übergeben Sie alle relevanten Parameter, die Sie möglicherweise verwenden oder nicht. Auf diese Weise können Sie problemlos Standardwerte für Attribute angeben. Unten ist ein Beispiel.
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; }
}
}
Nehmen wir an, Sie haben einen Klassennamen mit dem Namen Products und ein IsActive-Feld. Sie benötigen lediglich einen Konstruktor zum Erstellen:
Public class Products
{
public Products()
{
IsActive = true;
}
public string Field1 { get; set; }
public string Field2 { get; set; }
public bool IsActive { get; set; }
}
Dann ist Ihr IsActive-Standardwert True!
Bearbeiten :
Wenn Sie dies mit SQL tun möchten, verwenden Sie diesen Befehl:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.IsActive)
.HasDefaultValueSql("true");
}
In EF Core, das am 27. Juni 2016 veröffentlicht wurde, können Sie die fließende API zum Festlegen des Standardwerts verwenden. Wechseln Sie zur ApplicationDbContext-Klasse, suchen / erstellen Sie den Methodennamen OnModelCreating und fügen Sie die folgende fließende API hinzu.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<YourTableName>()
.Property(b => b.Active)
.HasDefaultValue(true);
}
In .NET Core 3.1 können Sie in der Modellklasse Folgendes ausführen:
public bool? Active { get; set; }
In DbContext OnModelCreating fügen Sie den Standardwert hinzu.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Foundation>()
.Property(b => b.Active)
.HasDefaultValueSql("1");
base.OnModelCreating(modelBuilder);
}
Daraus ergibt sich Folgendes in der Datenbank
Hinweis: Wenn Sie für Ihre Eigenschaft keine Nullable (bool?) Haben, wird die folgende Warnung angezeigt
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'.
Ich habe festgestellt, dass es ausreicht, nur den Auto-Property Initializer für die Entitätseigenschaft zu verwenden, um die Aufgabe zu erledigen.
Beispielsweise:
public class Thing {
public bool IsBigThing{ get; set; } = false;
}
Hmm ... ich mache zuerst DB und in diesem Fall ist das tatsächlich viel einfacher. EF6 richtig? Öffnen Sie einfach Ihr Modell, klicken Sie mit der rechten Maustaste auf die Spalte, für die Sie einen Standard festlegen möchten, wählen Sie Eigenschaften aus und Sie sehen ein Feld "DefaultValue". Füllen Sie das einfach aus und speichern Sie es. Es wird den Code für Sie einrichten.
Ihr Kilometerstand kann jedoch je nach Code variieren. Damit habe ich noch nicht gearbeitet.
Das Problem bei vielen anderen Lösungen besteht darin, dass sie zwar anfänglich funktionieren, aber sobald Sie das Modell neu erstellen, den von Ihnen in die maschinengenerierte Datei eingefügten benutzerdefinierten Code ausgeben.
Diese Methode fügt der edmx-Datei eine zusätzliche Eigenschaft hinzu:
<EntityType Name="Thingy">
<Property Name="Iteration" Type="Int32" Nullable="false" **DefaultValue="1"** />
Und indem Sie dem Konstruktor den erforderlichen Code hinzufügen:
public Thingy()
{
this.Iteration = 1;
Legen Sie den Standardwert für die Spalte in der Tabelle in MSSQL Server und im Klassencode-Attribut add wie folgt fest:
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
für die gleiche Eigenschaft.
this.Active = true;? Ich denke, der DB-Wert hat beim Abrufen Vorrang, aber seien Sie vorsichtig, wenn Sie neu sind, und fügen Sie dann zuerst eine Entität für ein Update ohne Abruf hinzu, da die Änderungsverfolgung dies möglicherweise sieht, wenn Sie den Wert aktualisieren möchten. Kommentar, weil ich EF schon lange nicht mehr verwendet habe und ich denke, dass dies ein Schuss in die Dunkelheit ist.