你实际上不会得到你希望的答案,仅仅因为这是不可能的。(N)Hibernate 是一个 Object-Relational-Mapping 框架,支持三种映射策略:
formula
它还允许您通过使用or等来偏离这一点sql-insert
,但是正如您所发现的,这些最终只会给您带来更多痛苦,Hibernate 社区不鼓励您,并且不利于您的代码的可维护性。
解决方案?
实际上,这很简单。您不想为Role
. 我假设您的意思是您不想公开Role 类型的类,并且您不想一直键入prObject.Role.Name
。Just prObject.Role
,它应该返回一个字符串。你有几个选择:
- 在 PersonRole 中使用内部类,这个类可以是内部的或私有的。添加设置和更新成员字段的属性角色;
- 使用内部类。添加设置和更新成员字段的属性角色;
让我们检查选项 2:
// mapped to table Role, will not be visible to users of your DAL
// class can't be private, it's on namespace level, it can when it's an inner class
internal class Role
{
// typical mapping, need not be internal/protected when class is internal
// cannot be private, because then virtual is not possible
internal virtual int Id { get; private set; }
internal virtual string Name { get; set; }
}
// the composite element
public class PersonRole
{
// mapped properties public
public virtual Person Person { get; set; }
// mapped properties hidden
internal virtual Role dbRole { get; set; }
// not mapped, but convenience property in your DAL
// for clarity, it is actually better to rename to something like RoleName
public string Role /* need not be virtual, but can be */
{
get
{
return this.dbRole.Name;
}
set
{
this.dbRole.Name = value; /* this works and triggers the cascade */
}
}
}
并且映射看起来像预期的那样。结果:您没有违反每类一个表的规则(编辑:asker 说他明确想要违反该规则,并且 Hib 支持它,这是正确的),但是您已经隐藏了对象,无法修改和访问通过使用典型的面向对象技术。所有 NH 功能(级联等)仍按预期工作。
(N)Hibernate 就是关于这种类型的决策:如何在不牺牲清晰度、简洁性或可维护性或违反 OO 或 ORM 规则的情况下为您的数据库制定一个经过深思熟虑且安全的抽象层。
更新(在 q. 关闭后)
在处理此类问题时,我经常使用的其他出色方法是:
正常创建映射(即,每个表一个类,我知道您不喜欢它,但这是最好的)并使用扩展方法:
// trivial general example
public static string GetFullName(this Person p)
{
return String.Format("{0} {1}", p.FirstName, p.LastName);
}
// gettor / settor for role.name
public static string GetRoleName(this PersonRole pr)
{
return pr.Role == null ? "" : pr.Role.Name;
}
public static SetRoleName(this PersonRole pr, string name)
{
pr.Role = (pr.Role ?? new Role());
pr.Role.Name = name;
}
正常创建映射但使用partial class
es,它使您能够以任何您喜欢的方式“装饰”您的类。优点:如果您使用生成的表映射,您可以根据需要多次重新生成。当然,部分类应该放在单独的文件中,因此考虑到您希望减少“膨胀”,这可能不是一个好的场景。
public partial class PersonRole
{
public string Role {...}
}
也许最简单:只是重载ToString()
for Role
,这使它适合在String.Format
和朋友中使用,但当然不会使其可分配。默认情况下,每个实体类或 POCO 都应该有一个ToString()
重载。
虽然可以直接使用 NHibernate 执行此操作,但 q. 在我有时间看之前已经关闭(没有人错,我只是没有时间)。如果我有时间通过 Hibernate HBM 映射进行更新,我会更新,即使我不同意这种方法。当最终结果对其他程序员来说不太清楚且整体不太清楚时,与 Hib 的高级概念搏斗是不好的(该表去了哪里?为什么该表没有 IDao 抽象?另请参阅NHibernate 最佳实践和S#arp)。然而,这个练习还是很有趣的。
考虑到“最佳实践”的评论:在典型情况下,不应该只是“一个表一个类”,而是每个表一个IDaoXXX,一个DaoConcreteXXX和一个GetDaoXXX,您使用类/接口层次结构来区分只读和读/写表。每个表至少有四个类/代码行。这通常是自动生成的,但为您的数据层 (dal) 提供了非常清晰的访问层 (dao)。数据层最好尽可能保持简洁。这些“最佳实践”都不会阻止您使用扩展方法或部分方法Role.Name
进入Role
.
这些是最佳的一般做法。在某些特殊或典型情况下,这并不总是可能或可行甚至是必要的。