webentwicklung-frage-antwort-db.com.de

Eindeutiger Schlüssel zuerst mit EF-Code

Ich habe ein folgendes Modell in meinem Projekt

public class Category
{   
    public Guid ID { get; set; }
    [Required(ErrorMessage = "Title cannot be empty")]
    public string Title { get; set; }
}

und ich versuche Title als eindeutigen Schlüssel festzulegen, habe nach der Lösung gegoogelt, aber keine gefunden. Kann mir jemand empfehlen, wie es geht, bitte?

Leider können Sie es nicht zuerst als eindeutigen Schlüssel im Code definieren, da EF überhaupt keine eindeutigen Schlüssel unterstützt (dies ist hoffentlich für die nächste Hauptversion geplant). Sie können einen benutzerdefinierten Datenbank-Intializer erstellen und einen eindeutigen Index manuell hinzufügen, indem Sie den SQL-Befehl aufrufen:

public class MyInitializer : CreateDatabaseIfNotExists<MyContext>
{
  protected override void Seed(MyContext context)
  {
    context.Database.ExecuteSqlCommand("CREATE UNIQUE INDEX IX_Category_Title ON Categories (Title)");
  }
}

Und Sie müssen diesen Initialisierer im bootstrap Ihrer Anwendung einstellen.

Database.SetInitializer<MyContext>(new MyInitializer());

Bearbeiten

Jetzt (ab EF 6.1) können Sie leicht eindeutige Einschränkungen haben,

[Index("TitleIndex", IsUnique = true)]
 public string Title { get; set; }
108
Ladislav Mrnka

Erstellen Sie zuerst die benutzerdefinierte Attributklasse:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class UniqueAttribute : ValidationAttribute
{
   public override Boolean IsValid(Object value)
    {
        // constraint implemented on database
        return true;
    }
}

Dann ergänzen Sie Ihre Klassen:

public class Email
{
    [Key]
    public int EmailID { get; set; }

    public int PersonId { get; set; }

    [Unique]
    [Required]
    [MaxLength(100)]
    public string EmailAddress { get; set; }
    public virtual bool IsDefault { get; set; }
    public virtual Boolean IsApprovedForLogin { get; set; }
    public virtual String ConfirmationToken { get; set; }

    [ForeignKey("PersonId")]
    public virtual Person Person { get; set; }
}

Fügen Sie dann einen Initialisierer in Ihren DbContext ein:

public class Initializer : IDatabaseInitializer<myEntities>
{
    public void InitializeDatabase(myEntities context)
    {
        if (System.Diagnostics.Debugger.IsAttached && context.Database.Exists() && !context.Database.CompatibleWithModel(false))
        {
            context.Database.Delete();
        }

        if (!context.Database.Exists())
        {
            context.Database.Create();

            var contextObject = context as System.Object;
            var contextType = contextObject.GetType();
            var properties = contextType.GetProperties();
            System.Type t = null;
            string tableName = null;
            string fieldName = null;
            foreach (var pi in properties)
            {
                if (pi.PropertyType.IsGenericType && pi.PropertyType.Name.Contains("DbSet"))
                {
                    t = pi.PropertyType.GetGenericArguments()[0];

                    var mytableName = t.GetCustomAttributes(typeof(TableAttribute), true);
                    if (mytableName.Length > 0)
                    {
                        TableAttribute mytable = mytableName[0] as TableAttribute;
                        tableName = mytable.Name;
                    }
                    else
                    {
                        tableName = pi.Name;
                    }

                    foreach (var piEntity in t.GetProperties())
                    {
                        if (piEntity.GetCustomAttributes(typeof(UniqueAttribute), true).Length > 0)
                        {
                            fieldName = piEntity.Name;
                            context.Database.ExecuteSqlCommand("ALTER TABLE " + tableName + " ADD CONSTRAINT con_Unique_" + tableName + "_" + fieldName + " UNIQUE (" + fieldName + ")");
                        }
                    }
                }
            }
        }
    }
}

Fügen Sie zuletzt den Initializer bei Application_Start in Global.asax.cs hinzu

System.Data.Entity.Database.SetInitializer<MyApp.Models.DomainModels.myEntities>(new MyApp.Models.DomainModels.myEntities.Initializer());

Das ist es. basierend auf dem vb code unter https://stackoverflow.com/a/742677

22
Joao Leme

Hier ist die VB.Net-Version - beachten Sie die Implementierung von Generika, die auf Klassenebene etwas anders ist.

Public Class MyInitializer(Of T As DbContext)
    Inherits CreateDatabaseIfNotExists(Of T)
    Protected Overrides Sub Seed(context As T)
        context.Database.ExecuteSqlCommand("CREATE UNIQUE INDEX IX_Category_Title ON Categories (Title)")
    End Sub
End Class
2
GilShalit

Ich habe diese Lösung gefunden, die zwar keinen eindeutigen Schlüssel in der SQL-Ebene erstellt, jedoch die Validierung von DataAnnotations verwendet. Probieren Sie es aus:

http://blogs.Microsoft.co.il/blogs/shimmy/archive/2012/01/23/validationattribute-that-validates-a-unique-field-against-its-fellow-rows-in- the-database.aspx

0
Shimmy

Ich erstelle diese Klasse (die von einer anderen Stackoverflow-Antwort erweitert wurde - Ausführen eines großen SQL-Skripts (mit GO-Befehlen) ), mit der ich die SQL-Skripts in ein Verzeichnis ablegen und sie alle ausführen lassen kann jedes Mal, wenn sie benötigt werden (Seed oder Migration). Ich werde dies nach der Bereitstellung für die Produktion nicht offen lassen, aber während der Entwicklung ist es einfach, Skripts bei jeder Neuerstellung der Datenbank anzuwenden.

using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//dll Microsoft.SqlServer.Smo
//dll Microsoft.SqlServer.Management.Sdk.Sfc
//dll Microsoft.SqlServer.ConnectionInfo
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;
using Monitor.Common;

namespace MonitorDB.DataLayer.Migrations
{
  public class ExecuteSQLScripts :Monitor.Common.ExceptionHandling
  {
    public ExecuteSQLScripts()
    {
}

public bool ExecuteScriptsInDirectory(DBContext.SolArcMsgMonitorContext context, string scriptDirectory)
{
  bool Result = false;
  try
  {
    SqlConnection connection = new SqlConnection(context.Database.Connection.ConnectionString);
    Server server = new Server(new ServerConnection(connection));

    DirectoryInfo di = new DirectoryInfo(scriptDirectory);
    FileInfo[] rgFiles = di.GetFiles("*.sql");
    foreach (FileInfo fi in rgFiles)
    {

      FileInfo fileInfo = new FileInfo(fi.FullName);
      string script = fileInfo.OpenText().ReadToEnd();

      server.ConnectionContext.ExecuteNonQuery(script);
    }
    Result = true;
  }
  catch (Exception ex)
  {
    CatchException("ExecuteScriptsInDirectory", ex);
  }
  return Result;
}

}}

So sieht die VS-Lösung aus:

0
codeputer