如何按照约定首先删除代码中的下划线外键字段

And*_*ier 50 entity-framework naming-conventions code-first entity-framework-6

我的项目中有多个课程(包括TPT).每个POCO具有BaseClass,其中有一个GUID(称为GlobalKey)作为主键.

首先我用来DataAnnotations创建正确的外键.但是,我在将对应的GUID与对象本身同步时遇到了问题.

现在我想只有一个虚拟导航属性,以便创建数据库中的GUID字段NamingConvention.但是字段名称总是添加一个下划线,后跟单词GlobalKey(右边).当我想删除下划线时,我不想通过流畅的API通过我的所有POCO来执行此操作:

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

是否有任何想法通过覆盖惯例为所有POCOS做到这一点?

提前致谢.

安德烈亚斯

cri*_*mbo 67

我终于通过编写自定义约定找到了答案.此约定适用于EF 6.0 RC1(上周的代码),因此我认为在EF 6.0发布后它可能会继续工作.

使用此方法,标准EF约定标识独立关联(IAs),然后为外键字段创建EdmProperty.然后,此约定出现并重命名外键字段.

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

}
Run Code Online (Sandbox Code Playgroud)

请注意,使用以下内容将"约定"添加到您DbContextDbContext.OnModelCreating覆盖中:

modelBuilder.Conventions.Add(new ForeignKeyNamingConvention());
Run Code Online (Sandbox Code Playgroud)

  • 最后,您可以在ForeignKeyIndexConvention之前添加约定,以将命名约定应用于外键索引名称--- modelBuilder.Conventions.AddBefore <System.Data.Entity.ModelConfiguration.Conventions.ForeignKeyIndexConvention>(new ForeignKeyNamingConvention()) ;` (9认同)
  • 你看!微软"借用"了我对MSDN的回答:http://msdn.microsoft.com/en-us/data/dn469439.aspx#example2因为他们对EF和ASP.NET这样的开源项目非常棒,我很高兴让它滑落...... (4认同)

Chr*_*att 5

你可以做以下两件事之一:

  1. 在命名外键时遵循EF约定,即如果您有虚拟Address,则将您的密钥属性定义为AddressId

  2. 告诉EF明确使用什么.一种方法是使用Fluent API,就像您目前所做的那样.您也可以使用数据注释:

    [ForeignKey("Address")]
    public int? AddressGlobalKey { get; set; }
    
    public virtual Address Address { get; set; }
    
    Run Code Online (Sandbox Code Playgroud)

那是你唯一的选择.


cov*_*ovo 5

我知道这有点旧,但这里有一个示例我如何通过我的流畅配置(OnModelCreating)指定映射列:

modelBuilder.Entity<Application>()
            .HasOptional(c => c.Account)
                .WithMany()
                .Map(c => c.MapKey("AccountId"));
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助,