接受接口进入nHibernate的收集(协方差)问题

接受接口进入nHibernate的收集(协方差)问题,nhibernate,fluent-nhibernate,c#-4.0,Nhibernate,Fluent Nhibernate,C# 4.0,我正在ASP.NET MVC应用程序中使用Fluent nHibernate作为持久层,我遇到了一些问题 我有一种情况,我需要使用抽象将对象存储到集合中,在这种情况下,如果从纯C#的角度来看,接口是最合乎逻辑的选择 基本上,一个对象(项)可以有需求。需求可以是很多东西。在本机C#情况下,我只需使用以下代码即可完成此任务 interface IRequirement { // methods and properties neccessary for evaluation } class It

我正在ASP.NET MVC应用程序中使用
Fluent nHibernate
作为持久层,我遇到了一些问题

我有一种情况,我需要使用抽象将对象存储到集合中,在这种情况下,如果从纯C#的角度来看,接口是最合乎逻辑的选择

基本上,一个对象(
)可以有
需求
。需求可以是很多东西。在本机C#情况下,我只需使用以下代码即可完成此任务

interface IRequirement
{
 // methods and properties neccessary for evaluation
}

class Item
{
 virtual int Id { get; set; }
 virtual IList<IRequirement> Requirements { get; set; }
}
那么,有人有什么想法吗?我似乎也不能使用泛型,所以创建一个基本的
需求
类型似乎不太合适。我的意思是代码可以工作和运行,但ORM无法掌握它。我意识到我在这里问的可能是不可能的,但我能做的就是问

我还想补充一点,我在
nHibernate
方面没有太多经验,只有
Fluent nHibernate
,但我已经意识到这两个社区都非常好,因此我将其标记为两者。但我目前的映射是100%的“流畅”

编辑 事实上,我发现它有点涉及到这一点,但我仍然不确定它是否适用于我的场景。感谢您的帮助

更新(2011年2月2日) 我添加此更新是为了回应发布的一些答案,因为我的结果是。。。有点尴尬

我接受了建议,做了更多的研究,设计了一个基本的界面

interface IRequirement
{
 // ... Same as it always was
}
现在我建立了我的类映射

class IRequirementMap : ClassMap<IRequirement>
{
 public IRequirementMap()
 {
    Id( x => x.Id );
    UseUnionSubclassForInheritanceMapping();
    Table("Requirements");
 }
}
尝试添加到该集合失败(正如我预期的那样)。这就是为什么我感到困惑

  • 如果我可以在会话中添加到generic
    IList
    ,为什么不在对象中添加呢
  • nHibernate如何理解具有相同Id的两个实体之间的差异, 如果它们都映射为同一种对象,在一种场景中,而不是在另一种场景中
有人能给我解释一下这到底是怎么回事吗

建议的方法是使用
子类映射
,但问题是标识的数量和表的大小。如果多个对象(最多8个)引用一个表中的标识,我会担心可伸缩性和性能。有人能给我一些具体的见解吗


请查看参考文档中的章节。在本章中,您可以看到使用哪种映射策略可以实现什么

据我所知,您选择了一种“每个具体类的表”策略。您可能需要
inverse=true
来映射它

如果要避免这种情况,需要将
irerequirement
作为基类映射到一个表中,然后可以将外键映射到该表中。这样,您就可以将其转换为“每个类的表层次结构”或“每个子类的表”映射。如果已经映射了另一个基类,这当然是不可能的。例如,
某种对象


编辑:有关
使用
逆=true和
的更多信息

当您使用
时,外键实际上位于指向项目的需求表中。到目前为止,这种方法效果很好,可以使用所有需求表来查找列表中的所有项。反转是必需的,因为它强制您拥有从需求到项目的引用,NH使用该引用构建外键

更灵活。它将列表存储在附加的链接表中。此表有三列:

  • 项的外键
  • 实际需求类型的名称(.NET类型或实体名称)
  • 以及需求的主键(不能是外键,因为它可能指向不同的表)
当NH读取此表时,它从类型信息(以及相应的需求映射)中知道需求所在的其他表。这就是任何类型的工作方式

它实际上是一个多对多关系,这不应该困扰您,它只意味着它将该关系存储在一个附加表中,从技术上讲,该表能够将需求链接到多个项目


编辑2:异常结果:

您映射了3个表:
irerequirement
实现requirement
的对象,
另一个具有requirement
的对象。他们都是完全独立的。您仍然在“每个具有隐式多态性的具体类的表”上。您刚刚添加了另一个包含
irerequirements
的表,当NH试图找到正确的表时,这也可能导致一些歧义

当然,结果是1,1。具有独立的表,因此具有以1开头的独立ID

起作用的部分:NHibernate在查询接口时,能够在整个数据库中找到实现接口的所有对象。尝试
session.CreateQuery(“从对象”)
可以得到整个数据库

不起作用的部分:另一方面,您不能仅通过id和接口或
对象
获取对象。因此,
session.Get(1)
不起作用,因为有许多id为1的对象。列表也存在同样的问题。还有一些问题,例如,对于隐式多态性,没有指定从实现
irerequirement
的每个类型指向项的外键

任意类型:这就是任意类型映射的用武之地。任何类型都与其他类型信息一起存储在数据库中,这是由
映射完成的,该映射将外键和类型信息存储在其他表中。有了这些额外的类型信息,NH就能够找到存储记录的表

怪胎队
class IRequirementMap : ClassMap<IRequirement>
{
 public IRequirementMap()
 {
    Id( x => x.Id );
    UseUnionSubclassForInheritanceMapping();
    Table("Requirements");
 }
}
class ObjectThatImplementsRequirementMap : ClassMap<ObjectThatImplementsRequirement>
{
 ObjectThatImplementsRequirementMap()
 {
  Id(x => x.Id); // Yes, I am base-class mapping it.
  // other properties
  Table("ObjectImplementingRequirement");
 }
}

class AnotherObjectThatHasRequirementMap : ClassMap<AnotherObjectThatHasRequirement>
    {
     AnotherObjectThatHasRequirementMap ()
     {
      Id(x => x.Id); // Yes, I am base-class mapping it.
      // other properties
      Table("AnotheObjectImplementingRequirement");
     }
}
// setup ISession
// setup Transaction
var requirements = new <IRequirement>
{
 new ObjectThatImplementsRequirement
 {
  // properties, etc.. 
 },
 new AnotherObjectThatHasRequirement
 {
  // other properties.
 }
}
// add to session.
// commit transaction.
// close writing block.

// setup new session
// setup new transaction
var requireables = session.Query<IRequirable>();
foreach(var requireable in requireables)
   Console.WriteLine( requireable.Id );
class SomethingThatHasRequireables
{ 
 // ...
 public virtual IList<IRequirement> Requirements { get; set; }
}