it-swarm.com.de

Entity Framework 6 Code first Standardwert

gibt es eine "elegante" Möglichkeit, einer bestimmten Eigenschaft einen Standardwert zu geben?

Vielleicht von DataAnnotations, etwa so:

[DefaultValue("true")]
public bool Active { get; set; }

Vielen Dank.

167
marino-krk

Sie können dies tun, indem Sie den Code zuerst manuell bearbeiten:

public override void Up()
{    
   AddColumn("dbo.Events", "Active", c => c.Boolean(nullable: false, defaultValue: true));
} 
143
devi

Es ist eine Weile her, aber ich habe eine Notiz für andere hinterlassen ... Ich habe erreicht, was mit einem Attribut benötigt wird, und ich habe meine Modellklassenfelder mit diesem Attribut versehen, wie ich möchte.

[SqlDefaultValue(DefaultValue = "getutcdate()")]
public DateTime CreatedDateUtc { get; set; }

Bekam die Hilfe von diesen 2 Artikeln:

Was ich getan habe:

Attribut definieren

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class SqlDefaultValueAttribute : Attribute
{
    public string DefaultValue { get; set; }
}

Im "OnModelCreating" des Kontextes

modelBuilder.Conventions.Add( new AttributeToColumnAnnotationConvention<SqlDefaultValueAttribute, string>("SqlDefaultValue", (p, attributes) => attributes.Single().DefaultValue));

Im benutzerdefinierten SqlGenerator

private void SetAnnotatedColumn(ColumnModel col)
{
    AnnotationValues values;
    if (col.Annotations.TryGetValue("SqlDefaultValue", out values))
    {
         col.DefaultValueSql = (string)values.NewValue;
    }
}

Registrieren Sie dann im Konstruktionskonfigurator für die Migrationskonfiguration den benutzerdefinierten SQL-Generator.

SetSqlGenerator("System.Data.SqlClient", new HarmonyMigrationSqlGenerator());
61
ravinsp

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 Attribut Standardwert entfernen. Der vorherige Standardwert bleibt also in der Datenbank erhalten.

Hier finden Sie eine vollständige Lösung des Problems, einschließlich der Entfernung von SQL-Einschränkungen beim Entfernen von Attributen .. __ Ich verwende auch das native DefaultValue-Attribut von .NET Framework.

Verwendungszweck

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
[DefaultValue("getutcdate()")]
public DateTime CreatedOn { get; set; }

Damit dies funktioniert, müssen Sie die Dateien IdentityModels.cs und Configuration.cs aktualisieren

IdentityModels.cs-Datei

Diese Methode in Ihrer ApplicationDbContext-Klasse hinzufügen/aktualisieren

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);
}

Datei Configuration.cs

Aktualisieren Sie Ihren Configuration-Klassenkonstruktor, indem Sie den 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 = [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;
    }
}
53

Ihre Modelleigenschaften müssen nicht automatisch sein. Dies ist jedoch einfacher. Und das DefaultValue-Attribut besteht eigentlich nur aus informativen Metadaten. Die Antwort akzeptiert hier 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 verwenden. Normalerweise ist dies kein Problem, wenn der Datenzugriffscode zentralisiert ist. Um den Wert in allen all - Anwendungen zu aktualisieren, müssen Sie die Datenquelle konfigurieren, um einen Standardwert festzulegen. Antwort von Devi zeigt, wie dies mit Migrationen, SQL oder der Sprache Ihrer Datenquelle möglich ist.

24
calebboyd

Was ich getan habe, habe ich Werte im Konstruktor der Entität initialisiert

Hinweis: DefaultValue-Attribute setzen die Werte Ihrer Eigenschaften nicht automatisch, sondern müssen dies selbst tun

8
Sameh Deabes

Nach dem Kommentar von @SedatKapanoglu füge ich all meine Ansätze hinzu, die funktionieren, weil er Recht hatte, nur die fließende API zu verwenden, funktioniert nicht.

1- Erstellen Sie einen benutzerdefinierten Code-Generator und überschreiben Sie Generate 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 fließend api, um die Annotation zu erstellen:

public static void Configure(DbModelBuilder builder){    
builder.Entity<Company>().Property(c => c.Status).HasColumnAnnotation("Default", 0);            
}
6
Denny Puig

Ich gebe zu, dass mein Ansatz dem gesamten "Code First" -Ansatz entgeht. Wenn Sie jedoch die Möglichkeit haben, den Standardwert in der Tabelle selbst zu ändern, ist dies 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 der Poster funktionieren:

[DefaultValue(true)]
public bool IsAdmin { get; set; }

Ich dachte, sie machten einfach den Fehler, Zitate hinzuzufügen ... aber leider keine solche Intuition. Die anderen Vorschläge waren einfach zu viel für mich (vorausgesetzt, ich habe die Privilegien, um in die Tabelle einzusteigen und die Änderungen vorzunehmen ... wo nicht in jeder Situation der Entwickler etwas tut). Am Ende habe ich es einfach auf die alte Art gemacht. Ich setze den Standardwert in der SQL Server-Tabelle ... Ich meine, wirklich schon genug! HINWEIS: Ich habe außerdem eine Add-Migrations- und Update-Datenbank getestet und die Änderungen stecken geblieben. enter image description here

2
Anthony Griggs

Überladen Sie einfach den Standardkonstruktor der Model-Klasse und übergeben Sie alle relevanten Parameter, die Sie verwenden können 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; }
    }

}
1
Bappa Malakar

Es ist einfach! Einfach kommentieren mit erforderlich.

[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 haben möchten, ändern Sie den Standardwert in der Migration vor der Aktualisierung der Datenbank in true

0