it-swarm.com.de

Wie entferne ich den Unterstrich von Fremdschlüsselfeldern im Code zuerst per Konvention?

Ich habe mehrere Klassen (einschließlich TPT) in meinem Projekt. Jedes POCO hat eine BaseClass, die als Primärschlüssel eine GUID (genannt GlobalKey) hat.

Zuerst habe ich DataAnnotations verwendet, um korrekte Fremdschlüssel zu erstellen. Ich habe jedoch Probleme, die entsprechende GUID mit dem Objekt selbst zu synchronisieren.

Jetzt möchte ich nur eine virtuelle Navigationseigenschaft haben, damit das GUID -Feld in der Datenbank von NamingConvention erstellt wird. Der Feldname fügt jedoch immer einen Unterstrich hinzu, gefolgt von dem Wort GlobalKey (was richtig ist). Wenn ich den Unterstrich entfernen möchte, möchte ich nicht durch alle meine POCOs in der fließenden API gehen, um dies zu tun:

// Remove underscore from Navigation-Field     
modelBuilder.Entity<Person>()
            .HasOptional(x => x.Address)
            .WithMany()
            .Map(a => a.MapKey("AddressGlobalKey"));

Irgendwelche Ideen, um dies für alle POCOS zu tun, indem Sie eine Konvention überschreiben?

Danke im Voraus.

Andreas

47
Andreas Geier

Ich fand schließlich eine Antwort darauf, indem ich eine benutzerdefinierte Konvention schrieb. Diese Konvention funktioniert in EF 6.0 RC1 (Code von letzter Woche). Ich denke, sie wird wahrscheinlich nach der Veröffentlichung von EF 6.0 weiterarbeiten.

Bei diesem Ansatz identifizieren die Standard-EF-Konventionen die unabhängigen Zuordnungen (IAs) und erstellen dann die EdmProperty für das Fremdschlüsselfeld. Dann kommt diese Konvention und benennt die Fremdschlüsselfelder um.

/// <summary>
/// Provides a convention for fixing the independent association (IA) foreign key column names.
/// </summary>
public class ForeignKeyNamingConvention : IStoreModelConvention<AssociationType>
{

    public void Apply(AssociationType association, DbModel model)
    {
        // Identify a ForeignKey properties (including IAs)
        if (association.IsForeignKey)
        {
            // rename FK columns
            var constraint = association.Constraint;
            if (DoPropertiesHaveDefaultNames(constraint.FromProperties, constraint.ToRole.Name, constraint.ToProperties))
            {
                NormalizeForeignKeyProperties(constraint.FromProperties);
            }
            if (DoPropertiesHaveDefaultNames(constraint.ToProperties, constraint.FromRole.Name, constraint.FromProperties))
            {
                NormalizeForeignKeyProperties(constraint.ToProperties);
            }
        }
    }

    private bool DoPropertiesHaveDefaultNames(ReadOnlyMetadataCollection<EdmProperty> properties, string roleName, ReadOnlyMetadataCollection<EdmProperty> otherEndProperties)
    {
        if (properties.Count != otherEndProperties.Count)
        {
            return false;
        }

        for (int i = 0; i < properties.Count; ++i)
        {
            if (!properties[i].Name.EndsWith("_" + otherEndProperties[i].Name))
            {
                return false;
            }
        }
        return true;
    }

    private void NormalizeForeignKeyProperties(ReadOnlyMetadataCollection<EdmProperty> properties)
    {
        for (int i = 0; i < properties.Count; ++i)
        {
            string defaultPropertyName = properties[i].Name;
            int ichUnderscore = defaultPropertyName.IndexOf('_');
            if (ichUnderscore <= 0)
            {
                continue;
            }
            string navigationPropertyName = defaultPropertyName.Substring(0, ichUnderscore);
            string targetKey = defaultPropertyName.Substring(ichUnderscore + 1);

            string newPropertyName;
            if (targetKey.StartsWith(navigationPropertyName))
            {
                newPropertyName = targetKey;
            }
            else
            {
                newPropertyName = navigationPropertyName + targetKey;
            }
            properties[i].Name = newPropertyName;
        }
    }

}

Beachten Sie, dass die Konvention Ihrer DbContext in Ihrer DbContext.OnModelCreating-Überschreibung hinzugefügt wird.

modelBuilder.Conventions.Add(new ForeignKeyNamingConvention());
66
crimbo

Sie haben zwei Möglichkeiten:

  1. Befolgen Sie die EF-Konventionen bei der Benennung von Fremdschlüsseln, d. H. Wenn Sie über virtuelles Address verfügen, definieren Sie Ihre Schlüsseleigenschaft als AddressId.

  2. Erklären Sie EF ausdrücklich, was Sie verwenden sollen. Eine Möglichkeit, dies zu tun, ist die Fluent-API, wie Sie es gerade tun. Sie können jedoch auch Datenanmerkungen verwenden:

    [ForeignKey("Address")]
    public int? AddressGlobalKey { get; set; }
    
    public virtual Address Address { get; set; }
    

Das ist deine einzige Wahl.

5
Chris Pratt

Ich weiß, das ist ein bisschen alt, aber hier ein Beispiel, wie ich Mapping-Spalten durch meine fließende Konfiguration (OnModelCreating) spezifiziere:

modelBuilder.Entity<Application>()
            .HasOptional(c => c.Account)
                .WithMany()
                .Map(c => c.MapKey("AccountId"));

Hoffe das hilft,

5
covo

Ich habe auch das gleiche Problem gesehen, wenn der Typ des Feldes deaktiviert ist. Überprüfen Sie den Typ des Feldes Ex:

public string StateId {get;set;}

auf ein Domänenobjekt mit int als Typ State.Id zeigt. Stellen Sie sicher, dass Ihre Typen gleich sind.

1
JimmyGoods

Die meisten dieser Antworten beziehen sich auf unabhängige Zuordnungen (wobei die Navigationseigenschaft "MyOtherTable" definiert ist, nicht jedoch die "int MyOtherTableId") anstelle von Fremdschlüsselzuordnungen (in denen beide definiert sind). 

Das ist in Ordnung, da es sich bei der Frage um IA handelt (es wird MapKey verwendet), aber ich bin auf diese Frage gestoßen, als ich nach einer Lösung für das gleiche Problem mit FKAs gesucht habe. Da andere Leute möglicherweise aus demselben Grund hierher kommen, dachte ich, ich würde meine Lösung teilen, die eine ForeignKeyDiscoveryConvention verwendet.

https://stackoverflow.com/a/43809004/799936

0
kevinpo

Ich habe festgestellt, dass wichtige Spaltenanpassungen von der ForeignKeyNamingConvention nicht erfasst wurden. Diese Änderung wurde vorgenommen, um sie zu fangen.

private bool DoPropertiesHaveDefaultNames(ReadOnlyMetadataCollection<EdmProperty> properties, string roleName, ReadOnlyMetadataCollection<EdmProperty> otherEndProperties)
{
    if (properties.Count == otherEndProperties.Count)
    {
        for (int i = 0; i < properties.Count; ++i)
        {
            if (properties[i].Name.EndsWith("_" + otherEndProperties[i].Name))
            {
                return true;
            }
            else
            {
                var preferredNameProperty =
                    otherEndProperties[i]
                        .MetadataProperties
                        .SingleOrDefault(x => x.Name.Equals("PreferredName"));

                if (null != preferredNameProperty)
                {
                    if (properties[i].Name.EndsWith("_" + preferredNameProperty.Value))
                    {
                        return true;
                    }
                }
            }
        }
    }
    return false;
}
0
Sean M

Ich hatte Probleme beim Kombinieren mit einer ID-Namenskonvention von EntityNameId. 

Wenn Sie die folgende Konvention verwenden, um sicherzustellen, dass in der Customer-Tabelle CustomerId statt nur Id angegeben ist. 

modelBuilder.Properties()
                        .Where(p => p.Name == "Id")
                        .Configure(p => p.IsKey().HasColumnName(p.ClrPropertyInfo.ReflectedType == null ? "Id" : p.ClrPropertyInfo.ReflectedType.Name +"Id"));

Die Benennungskonvention für Fremdschlüssel muss wie folgt geändert werden. 

 /// <summary>
    /// Provides a convention for fixing the independent association (IA) foreign key column names.
    /// </summary>
    public class ForeignKeyNamingConvention : IStoreModelConvention<AssociationType>
    { 
        public void Apply(AssociationType association, DbModel model) 
        { 
            // Identify ForeignKey properties (including IAs)  
            if (!association.IsForeignKey) return;

            // rename FK columns  
            var constraint = association.Constraint; 
            if (DoPropertiesHaveDefaultNames(constraint.FromProperties, constraint.ToProperties)) 
            { 
                NormalizeForeignKeyProperties(constraint.FromProperties); 
            } 

            if (DoPropertiesHaveDefaultNames(constraint.ToProperties, constraint.FromProperties)) 
            { 
                NormalizeForeignKeyProperties(constraint.ToProperties); 
            }
        } 

        private static bool DoPropertiesHaveDefaultNames(IReadOnlyList<EdmProperty> properties, IReadOnlyList<EdmProperty> otherEndProperties) 
        { 
            if (properties.Count != otherEndProperties.Count) 
            { 
                return false; 
            } 

            for (var i = 0; i < properties.Count; ++i)
            {
                if (properties[i].Name.Replace("_", "") != otherEndProperties[i].Name) 
                { 
                    return false; 
                } 
            } 

            return true; 
        } 

        private void NormalizeForeignKeyProperties(ReadOnlyMetadataCollection<EdmProperty> properties) 
        { 
            for (var i = 0; i < properties.Count; ++i) 
            { 
                var underscoreIndex = properties[i].Name.IndexOf('_'); 
                if (underscoreIndex > 0) 
                { 
                    properties[i].Name = properties[i].Name.Remove(underscoreIndex, 1); 
                }                 
            } 
        } 
    }
0
CountZero