如何在代码中首先删除下划线中的外键字段

我的项目中有多个类(包括TPT)。 每个POCO都有一个BaseClass ,它有一个GUID (称为GlobalKey )作为主键。

首先我使用DataAnnotations来创build正确的外键。 但是,我有问题同步相应的GUID与对象本身。

现在我只想要一个虚拟导航属性,以便数据库中的GUID字段由NamingConvention创build。 但字段名称总是加上一个下划线,后面跟着GlobalKey (这是正确的)。 当我想删除下划线时,我不想通过stream畅API中的所有POCO来执行此操作:

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

任何想法通过覆盖一个约定为所有POCOS做这个?

提前致谢。

安德烈亚斯

我终于find了一个答案,通过编写一个自定义约定。 这个约定适用于EF 6.0 RC1(上周的代码),所以我认为在EF 6.0发布之后很可能继续工作。

通过这种方法,标准的EF约定识别独立的关联(IAs),然后为外键字段创buildEdmProperty。 然后这个约定出现并重命名外键字段。

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

请注意,该公约已添加到您的DbContext.OnModelCreating覆盖您的DbContext.OnModelCreating ,使用:

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

你可以做两件事之一:

  1. 按照EF惯例命名外键,即如果您有虚拟Address ,请将您的密钥属性定义为AddressId

  2. 明确告诉EF要使用什么。 一种方法是使用Fluent API,就像你现在正在做的那样。 但是,您也可以使用数据注释:

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

这是你唯一的select。

我知道这是有点旧,但这里是一个示例如何通过我的stream利configuration(OnModelCreating)指定映射列:

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

希望这可以帮助,

当字段的typesclosures时,我也看到了同样的问题。 仔细检查字段的types例如:

 public string StateId {get;set;} 

用int作为State.Idtypes指向一个域对象。 确保你的types是相同的。

我发现关键列自定义没有被ForeignKeyNamingConvention捕获。 做了这个改变来抓住他们。

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

在将它与EntityNameId的id命名约定相结合时遇到了问题。

使用以下约定来确保Customer表具有CustomerId而不是简单的Id。

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

外键命名约定需要更改为以下内容。

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

这些答案中的大部分都与独立关联(“MyOtherTable”导航属性被定义,而不是“MyOtherTableId”)而不是外键关联(其中两个都被定义)有关。

这很好,因为这个问题是关于IA(它使用MapKey)的,但是当我用FKAsearch解决同样的问题的时候遇到了这个问题。 由于其他人可能出于同样的原因来到这里,我想我会分享我的解决scheme,使用ForeignKeyDiscoveryConvention。

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