Ho più classi (incluso TPT) nel mio progetto. Ogni POCO ha una BaseClass
, che ha un GUID
(chiamato GlobalKey
) come chiave primaria.
Per prima cosa ho usato DataAnnotations
per creare chiavi esterne corrette. Ma poi ho problemi a sincronizzare il GUID corrispondente con l'oggetto stesso.
Ora voglio avere solo una proprietà di navigazione virtuale in modo che il campo GUID nel database sia creato da NamingConvention
. Ma il nome del campo aggiunge sempre un trattino basso seguito dalla parola GlobalKey
(che è giusto). Quando voglio rimuovere il carattere di sottolineatura, non voglio passare attraverso tutti i miei POCO nell'API fluente per fare questo:
// Remove underscore from Navigation-Field
modelBuilder.Entity<Person>()
.HasOptional(x => x.Address)
.WithMany()
.Map(a => a.MapKey("AddressGlobalKey"));
Qualche idea per farlo per tutti i POCOS sovrascrivendo una convenzione?
Grazie in anticipo.
Andreas
Alla fine ho trovato una risposta per questo, scrivendo una convenzione personalizzata. Questa convenzione funziona con EF 6.0 RC1 (codice della scorsa settimana), quindi penso che probabilmente continuerà a funzionare anche dopo il rilascio di EF 6.0.
Con questo approccio, le convenzioni EF standard identificano le associazioni indipendenti (IA) e quindi creano la proprietà EdmProperty per il campo chiave esterna. Quindi questa convenzione arriva e rinomina i campi chiave stranieri.
/// <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;
}
}
}
Tieni presente che la convenzione viene aggiunta al tuo DbContext
nel tuo override di DbContext.OnModelCreating
, utilizzando:
modelBuilder.Conventions.Add(new ForeignKeyNamingConvention());
So che questo è un po 'vecchio, ma qui è un esempio di come specificare colonne di mappatura attraverso la mia fluente configurazione (OnModelCreating):
modelBuilder.Entity<Application>()
.HasOptional(c => c.Account)
.WithMany()
.Map(c => c.MapKey("AccountId"));
Spero che questo ti aiuti,