Fluent nhibernate 我可以创建一个包含父密钥名称的流畅的NHibernate外键约定吗?

Fluent nhibernate 我可以创建一个包含父密钥名称的流畅的NHibernate外键约定吗?,fluent-nhibernate,naming-conventions,Fluent Nhibernate,Naming Conventions,我有一个数据库模式,其中外键名称的约定是: ForeignTable.Name + ForeignTable.PrimaryKeyName 因此,对于引用具有名为key主键列的父表的子表,外键将类似于ParentKey 有没有办法在我的Fluent NHibernate映射中创建此约定 目前,我正在使用一个ForeignKeyConvention实现,如下所示: public class ForeignKeyNamingConvention : ForeignKeyConvention {

我有一个数据库模式,其中外键名称的约定是:

ForeignTable.Name + ForeignTable.PrimaryKeyName
因此,对于引用具有名为
key
主键列的
父表的
子表,外键将类似于
ParentKey

有没有办法在我的Fluent NHibernate映射中创建此约定


目前,我正在使用一个
ForeignKeyConvention
实现,如下所示:

public class ForeignKeyNamingConvention : ForeignKeyConvention
{
    protected override string GetKeyName(PropertyInfo property, Type type)
    {
        if (property == null)
        {
            // Relationship is many-to-many, one-to-many or join.
            if (type == null)
                throw new ArgumentNullException("type");

            return type.Name + "ID";
        }

        // Relationship is many-to-one.
        return property.Name + "ID";
    }
}
对于以“ID”作为主键的所有类型,这完全符合我的要求。我想做的是用被引用类型的主键的名称替换常量“ID”

如果Fluent NHibernate目前无法实现这一点,我很乐意接受这个答案。

请看一看,尤其是实现自定义外键约定


更新:

这里有一个例子。假设以下域:

public class Parent
{
    public virtual int Id { get; set; }
}

public class Child
{
    public virtual string Id { get; set; }
    public virtual Parent Parent { get; set; }
}
需要映射到此架构的:

create table Child(
    Id integer primary key, 
    ParentId integer
)

create table Parent(
    Id integer primary key
)
您可以使用此约定:

public class CustomForeignKeyConvention : IReferenceConvention
{
    public void Apply(IManyToOneInstance instance)
    {
        instance.Column(instance.Class.Name + "Id");
    }
}
要创建会话工厂,请执行以下操作:

var sf = Fluently
    .Configure()
    .Database(
        SQLiteConfiguration.Standard.UsingFile("data.db3").ShowSql()
    )
    .Mappings(
        m => m.AutoMappings.Add(AutoMap
            .AssemblyOf<Parent>()
            .Where(t => t.Namespace == "Entities")
            .Conventions.Add<CustomForeignKeyConvention>()
        )
    )
    .BuildSessionFactory();
var sf=流利
.Configure()
.数据库(
SQLiteConfiguration.Standard.UsingFile(“data.db3”).ShowSql()
)
.映射(
m=>m.AutoMappings.Add(自动映射

.Where(t=>t.Namespace==“实体”)
.Conventions.Add()
)
)
.BuildSessionFactory();

如果可以获取类的
映射,则可以获取其Id列的名称

public class MyForeignKeyConvention: ForeignKeyConvention
{
    public static IList<IMappingProvider> Mappings = new List<IMappingProvider>();

    protected override string GetKeyName( System.Reflection.PropertyInfo property, Type type )
    {
        var pk = "Id";

        var model = new PersistenceModel();
        foreach( var map in Mappings ) {
            model.Add( map );
        }

        try {
            var mymodel = (IdMapping) model.BuildMappings()
                .First( x => x.Classes.FirstOrDefault( c => c.Type == type ) != null )
                .Classes.First().Id;

            Func<IdMapping, string> getname = x => x.Columns.First().Name;
            pk = getname( mymodel );
        } catch {
        }

        if (property == null) {
            return type.Name + pk;
        }
        return type.Name + property.Name;
    }
}

对于一个全系统的会议,我认为这将最符合目的。 (由于我已经回答了,所以我不确定是把全文还是只包括其中的一部分)

以下是链接到当前Fluent NHibernate和自动映射文档的解决方案

问题(一个简单的例子): 假设您有一个简单的示例(来自fluent的wiki),其中有一个实体及其列表中的值对象:

public class Product
{
  public virtual int Id { get; set; }
  //..
  public virtual Shelf { get; set; }
}

public class Shelf
{
  public virtual int Id { get;  set; }
  public virtual IList<Product> Products { get; set; }

  public Shelf()
  {
    Products = new List<Product>();
  }
}
以及shelfid->Shelf.Id的外键


您将得到以下错误: 列名无效。。。货架标识


解决方案: 添加约定,可以是系统范围的约定,也可以是更严格的约定

ForeignKey.EndsWith("Id")
代码示例:

var cfg = new StoreConfiguration();
var sessionFactory = Fluently.Configure()
  .Database(/* database config */)
  .Mappings(m =>
    m.AutoMappings.Add(
      AutoMap.AssemblyOf<Product>(cfg)
          .Conventions.Setup(c =>
              {
                  c.Add(ForeignKey.EndsWith("Id"));
              }
    )
  .BuildSessionFactory();

ForeignKeyConvention
是我开始寻找的地方,但由于缺乏清晰的文档,很难理解从父类型中的相关信息。感谢更新,但它没有解决我的问题:在
Apply(IManyToOneInstance)
中如何获取父键列的名称?Name+“ID”不是我想要的行为。Name+Parent.KeyName是。没有PrimaryKeyName这样的概念。都是关于惯例的。按照惯例,所有主键列都应称为
Id
。您可以通过为给定类型或所有类型实现
IIdConvention
来更改此默认行为,这意味着您已经知道更改此默认行为的类型。因此,在
IReferenceConvention
中,根据类型,您可以应用适当的后缀。我的约定不要求表之间的主键名称一致,但外键总是
ForeignTable.name
+
ForeignTable.PrimaryKeyName
。如果这个概念不是当前约定模型所能提供的,我很高兴有一个答案可以这么说。@Programming Hero这一切都是从单元测试IdConventionTests中得到启发的。Column不应该被覆盖它并不像我所希望的那样是一个直接的解决方案,但是有足够的信息供我去探索。谢谢你,我必须改变这个。但是很有效,谢谢你。向上投票/*受保护重写字符串GetKeyName(System.Reflection.PropertyInfo属性,类型){*/受保护重写字符串GetKeyName(成员属性,类型){My(FluentNHibernate)版本(需要更改):1.3.0.733
ForeignKey.EndsWith("Id")
var cfg = new StoreConfiguration();
var sessionFactory = Fluently.Configure()
  .Database(/* database config */)
  .Mappings(m =>
    m.AutoMappings.Add(
      AutoMap.AssemblyOf<Product>(cfg)
          .Conventions.Setup(c =>
              {
                  c.Add(ForeignKey.EndsWith("Id"));
              }
    )
  .BuildSessionFactory();
Table.Is(x => x.EntityType.Name + "Table")
PrimaryKey.Name.Is(x => "ID")
AutoImport.Never()
DefaultAccess.Field()
DefaultCascade.All()
DefaultLazy.Always()
DynamicInsert.AlwaysTrue()
DynamicUpdate.AlwaysTrue()
OptimisticLock.Is(x => x.Dirty())
Cache.Is(x => x.AsReadOnly())
ForeignKey.EndsWith("ID")