entity framework - una - ¿Cómo elimino el subrayado de los campos de clave externa en el código primero por convención
restricciones sql (7)
Descubrí que las personalizaciones de columna clave no estaban siendo detectadas por ForeignKeyNamingConvention. Hizo este cambio para atraparlos.
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;
}
Tengo varias clases (incluido TPT) en mi proyecto. Cada POCO tiene una BaseClass
, que tiene un GUID
(llamado GlobalKey
) como clave principal.
Primero usé DataAnnotations
para crear claves externas correctas. Pero luego tengo problemas para sincronizar el GUID correspondiente con el objeto en sí.
Ahora quiero tener solo una propiedad de navegación virtual para que el campo GUID en la base de datos sea creado por NamingConvention
. Pero el nombre de campo siempre agrega un guión bajo seguido de la palabra GlobalKey
(que es correcta). Cuando quiero eliminar el guión bajo, no quiero pasar por todos mis POCO en la API fluida para hacer esto:
// Remove underscore from Navigation-Field
modelBuilder.Entity<Person>()
.HasOptional(x => x.Address)
.WithMany()
.Map(a => a.MapKey("AddressGlobalKey"));
¿Alguna idea de hacer esto para todos los POCOS sobrescribiendo una convención?
Gracias por adelantado.
Andreas
Finalmente encontré una respuesta para esto, escribiendo una convención personalizada. Esta convención funciona en EF 6.0 RC1 (código de la semana pasada), por lo que creo que es probable que continúe funcionando después de que se libere EF 6.0.
Con este enfoque, las convenciones EF estándar identifican las asociaciones independientes (IA) y luego crean EdmProperty para el campo clave externa. Luego viene esta convención y cambia el nombre de los campos de clave externa.
/// <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;
}
}
}
Tenga en cuenta que la Convención se agrega a su DbContext
en su sobrescritura DbContext.OnModelCreating
, usando:
modelBuilder.Conventions.Add(new ForeignKeyNamingConvention());
La mayoría de estas respuestas tienen que ver con asociaciones independientes (donde se define la propiedad de navegación "MyOtherTable", pero no el "int MyOtherTableId") en lugar de las asociaciones de claves foráneas (donde ambas están definidas).
Eso está bien ya que la pregunta es sobre IA (usa MapKey), pero me encontré con esta pregunta cuando buscaba una solución al mismo problema con las FKA. Dado que otras personas pueden venir aquí por la misma razón, pensé que compartiría mi solución que usa una ForeignKeyDiscoveryConvention.
https://.com/a/43809004/799936
Puedes hacer una de las dos cosas:
Siga las convenciones de EF al nombrar claves externas, es decir, si tiene una
Address
virtual, defina la propiedad clave comoAddressId
Dile a EF explícitamente qué usar. Una forma de hacerlo es con Fluent API, como lo está haciendo actualmente. También puedes usar anotaciones de datos:
[ForeignKey("Address")] public int? AddressGlobalKey { get; set; } public virtual Address Address { get; set; }
Esa es tu única opción.
Sé que esto es un poco viejo, pero aquí hay una muestra de cómo especifico columnas de mapeo a través de mi configuración fluida (OnModelCreating):
modelBuilder.Entity<Application>()
.HasOptional(c => c.Account)
.WithMany()
.Map(c => c.MapKey("AccountId"));
Espero que esto ayude,
También he visto el mismo problema cuando el tipo de campo está desactivado. Verifique dos veces el tipo del campo Ex:
public string StateId {get;set;}
apuntando a un objeto de dominio con int como el tipo State.Id. Asegúrate de que tus tipos sean iguales.
Tuve problemas al combinarlo con una convención de nomenclatura de identificación de EntityNameId.
Cuando utilice la siguiente convención para asegurarse de que la tabla Cliente tenga ID de cliente en lugar de simplemente ID.
modelBuilder.Properties()
.Where(p => p.Name == "Id")
.Configure(p => p.IsKey().HasColumnName(p.ClrPropertyInfo.ReflectedType == null ? "Id" : p.ClrPropertyInfo.ReflectedType.Name +"Id"));
La convención de nomenclatura de clave externa debe cambiarse a lo siguiente.
/// <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);
}
}
}
}