Fluent NHibernate 自动映射:如何自定义子类表名称和键列名称?
我想这肯定是以前被问过的,但我用谷歌搜索了一个小时但找不到答案。
假设我有以下 2 个模型:
public class Organism
{
public virtual int Id { get; private set; }
}
public class Animal : Organism
{
}
我希望 Fluent NHibernate 为我创建下表:
OrganismTable
OrganismId
AnimalTable
AnimalId
这可以通过使用手动映射轻松实现:
public class OrganismMappinig : ClassMap<Organism>
{
public OrganismMappinig()
{
Table("OrganismTable");
Id(x => x.Id).Column("OrganismId");
}
}
public class AnimalMapping : SubclassMap<Animal>
{
public AnimalMapping()
{
Table("AnimalTable");
KeyColumn("AnimalId");
}
}
但我无法使用自动映射获得相同的结果。我尝试添加以下约定:
public class TableNameConvension : IClassConvention, IClassConventionAcceptance
{
public void Apply(IClassInstance instance)
{
instance.Table(instance.EntityType.Name + "Table");
}
public void Accept(IAcceptanceCriteria<IClassInspector> criteria)
{
criteria.Expect(x => x.TableName, Is.Not.Set);
}
}
public class PrimaryKeyNameConvention : IIdConvention
{
public void Apply(IIdentityInstance instance)
{
instance.Column(instance.EntityType.Name + "Id");
}
}
它创建了这 2 个表:
OrganismTable (correct)
OrganismId (correct)
Animal (wrong, should be "AnimalTable")
Organism_id (wrong, should be "AnimalId")
我还尝试添加:
public class ForeignKeyColumnNameConvention : ForeignKeyConvention
{
protected override string GetKeyName(Member property, Type type)
{
if (property == null)
return type.Name + "Id";
return property.Name + "Id";
}
}
它创建了这 2 个表:
OrganismTable (correct)
OrganismId (correct)
Animal (wrong, should be "AnimalTable")
OrganismId (wrong, should be "AnimalId")
我还尝试添加:
public class AnimalOverride : IAutoMappingOverride<Animal>
{
public void Override(AutoMapping<Animal> mapping)
{
mapping.Table("AnimalTable");
mapping.Id(x => x.Id).Column("AnimalId");
}
}
它创建了以下表:
OrganismTable (correct)
OrganismId (correct)
AnimalTable (correct)
OrganismId (wrong, should be "AnimalId")
这正确地将表名称设置为“AnimalTable”(但这需要太多的手动输入,如果有一个可以得到相同结果的约定那就太好了),但未能将键列名称设置为“AnimalId”。
以下是我的其余代码:
class Program
{
static void Main(string[] args)
{
ISessionFactory sessionFactory = Fluently.Configure()
.Database(MsSqlConfiguration
.MsSql2008.ConnectionString(connectionString)
.ShowSql())
.Mappings(m => m.AutoMappings.Add(
AutoMap.Assemblies(typeof(Organism).Assembly)
.Conventions.AddAssembly(typeof(Program).Assembly)
.UseOverridesFromAssembly(typeof(Program).Assembly)))
.ExposeConfiguration(BuildSchema)
.BuildConfiguration()
.BuildSessionFactory();
}
static void BuildSchema(Configuration cfg)
{
new SchemaExport(cfg).Create(false, true);
}
}
有什么想法吗?谢谢。
I think this must have been asked before, but I have googled for an hour but couldn't find the answer.
Let's say I have the following 2 models:
public class Organism
{
public virtual int Id { get; private set; }
}
public class Animal : Organism
{
}
I want Fluent NHibernate to create the following tables for me:
OrganismTable
OrganismId
AnimalTable
AnimalId
This can be easily achieved by using manual mapping:
public class OrganismMappinig : ClassMap<Organism>
{
public OrganismMappinig()
{
Table("OrganismTable");
Id(x => x.Id).Column("OrganismId");
}
}
public class AnimalMapping : SubclassMap<Animal>
{
public AnimalMapping()
{
Table("AnimalTable");
KeyColumn("AnimalId");
}
}
But I can't get the same result using automapping. I tried to add the following conventions:
public class TableNameConvension : IClassConvention, IClassConventionAcceptance
{
public void Apply(IClassInstance instance)
{
instance.Table(instance.EntityType.Name + "Table");
}
public void Accept(IAcceptanceCriteria<IClassInspector> criteria)
{
criteria.Expect(x => x.TableName, Is.Not.Set);
}
}
public class PrimaryKeyNameConvention : IIdConvention
{
public void Apply(IIdentityInstance instance)
{
instance.Column(instance.EntityType.Name + "Id");
}
}
It created these 2 tables:
OrganismTable (correct)
OrganismId (correct)
Animal (wrong, should be "AnimalTable")
Organism_id (wrong, should be "AnimalId")
I also tried to add:
public class ForeignKeyColumnNameConvention : ForeignKeyConvention
{
protected override string GetKeyName(Member property, Type type)
{
if (property == null)
return type.Name + "Id";
return property.Name + "Id";
}
}
It created these 2 tables:
OrganismTable (correct)
OrganismId (correct)
Animal (wrong, should be "AnimalTable")
OrganismId (wrong, should be "AnimalId")
I also tried to add:
public class AnimalOverride : IAutoMappingOverride<Animal>
{
public void Override(AutoMapping<Animal> mapping)
{
mapping.Table("AnimalTable");
mapping.Id(x => x.Id).Column("AnimalId");
}
}
It created the following tables:
OrganismTable (correct)
OrganismId (correct)
AnimalTable (correct)
OrganismId (wrong, should be "AnimalId")
This correctly set table name to "AnimalTable" (but this takes too much manual typing, would be great if there is a convention that can get the same result), but failed to set key column name to "AnimalId".
Below is the rest of my code:
class Program
{
static void Main(string[] args)
{
ISessionFactory sessionFactory = Fluently.Configure()
.Database(MsSqlConfiguration
.MsSql2008.ConnectionString(connectionString)
.ShowSql())
.Mappings(m => m.AutoMappings.Add(
AutoMap.Assemblies(typeof(Organism).Assembly)
.Conventions.AddAssembly(typeof(Program).Assembly)
.UseOverridesFromAssembly(typeof(Program).Assembly)))
.ExposeConfiguration(BuildSchema)
.BuildConfiguration()
.BuildSessionFactory();
}
static void BuildSchema(Configuration cfg)
{
new SchemaExport(cfg).Create(false, true);
}
}
Any ideas? Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
当 FluentNHibernate 进行自动映射时,它使用每个具体类一个表来映射继承层次结构。由于 Organism 和 Animal 都是具体类型,因此它生成两个表:OrganismTable 和 AnimalTable。有机体表存储所有有机体共有的所有属性。 AnimalTable只存储Animal子类添加的属性。 AnimalTable 上的 PK 也是 OrganismTable 上的 FK。因此它受到你的 FK 约定的影响。请注意,PKNameConvention 仅适用于“有机体”,不适用于“动物”。类似地,FKColumnNameConvention 仅由 Animal 调用。由于 Animal FK 仅在内部用于连接继承层次结构,因此该属性为 null。因此,您将获得 OrganismId 作为 FK 名称。要设置此 PK/FK,您需要使用 IJoinedSubclassConvention。 (为了完整性,我已经包含了您的 TableNameConvention 和 PrimaryKeyNameConvention。)
这会生成:
带有从 AnimalTable.AnimalId 到 OrganismTable.OrganismId 的 FK。
请注意,由于查询实体时所需的联接数量,“每个具体类一个表”并不是我继承映射的首选。通常,每个子类一个表或每个类层次结构一个表是更好的选择。我将把它作为练习,让读者调查 NHibernate 文档中关于 继承策略。
When FluentNHibernate is automapping, it uses table-per-concrete-class for mapping inheritance hierarchies. Since Organism and Animal are both concrete types, it generates two tables, OrganismTable and AnimalTable. OrganismTable stores all the properties common with all Organisms. AnimalTable only stores the properties added by the Animal subclass. The PK on AnimalTable is also a FK to OrganismTable. Hence it being affected by your FK convention. Note that PKNameConvention is only called for Organism and not for Animal. Similarly FKColumnNameConvention is only called by Animal. Because the Animal FK is only used internally to hook up the inheritance hierarchy, the property is null. Hence you're getting OrganismId as the FK name. To set this PK/FK, you need to use an IJoinedSubclassConvention. (I've included your TableNameConvention and PrimaryKeyNameConvention for completeness.)
This generates:
with a FK from AnimalTable.AnimalId to OrganismTable.OrganismId.
Please note that table-per-concrete-class is not my preferred choice for inheritance mapping due to the number of joins required when querying entities. Often table-per-subclass or table-per-class-hierarchy are better choices. I'll leave it as an exercise for the reader to investigate the differences in the NHibernate documentation on inheritance strategies.