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")