NHibernate转换问题(可疑原因是映射不正确)

时间:2011-10-19 16:34:27

标签: c# .net nhibernate mapping

我在NHibernate中映射Petition和PetitionSignature之间的M:1关系时遇到了麻烦。这是我以前映射过的一种关系,但我现在无法正常工作。

我试图在我的提供程序中调用的方法旨在根据传入的Petition对象返回PetitionSignatures的集合:

public IList<PetitionSignature> GetByPetition(Petition p)
{
    IList<PetitionSignature> Signatures = (IList<PetitionSignature>)_session.CreateCriteria(typeof(PetitionSignature))
        .Add(Restrictions.Eq("Petition", p))
        .AddOrder(Order.Desc("Id")).List();
    return Signatures.OrderBy(sig => sig.Date).ToList();
}

我的请愿课被定义为:

public class Petition : IPetition
{
    public virtual int Id { get; set; }
    public virtual string Title { get; set; }
    public virtual string Text { get; set; }
    public virtual string Slug { get; set; }
    public virtual DateTime Date { get; set; }
    public virtual IList<PetitionSignature> Signatures { get; set; }
}

我的PetitionSignature类定义为:

public class PetitionSignature : IPetitionSignature
{
    public virtual int Id { get; set; }
    public virtual Petition Petition { get; set; }
    public virtual string Name { get; set; }
    public virtual string EmailAddress { get; set; }
    public virtual string PhoneNumber { get; set; }
    public virtual string StreetAddress { get; set; }
    public virtual DateTime Date { get; set; }
    public virtual bool OkToEmail { get; set; }

}

我的请愿书映射文件是:

<id name="Id" column="Id" type="int">
  <generator class="native" />
</id>

<property name="Title" column="Title"></property>
<property name="Text" column="Text"></property>
<property name="Date" column="Date"></property>
<property name="Slug" column="Slug"></property>

<bag name="Signatures" lazy="true" cascade="all-delete-orphan" inverse="true">
  <key column="Id"/>
  <one-to-many class="PetitionSignature"/>
</bag>

我的PetitionSignature制图文件如下:

                

<property name="Name" column="Name"></property>
<property name="EmailAddress" column="EmailAddress"></property>
<property name="Date" column="Date"></property>
<property name="OkToEmail" column="OkToEmail"></property>
<property name="PhoneNumber" column="PhoneNumber"></property>
<property name="StreetAddress" column="StreetAddress"></property>

  <many-to-one name="Petition" class="Petition" column="Petition" cascade="all" />

这些是我的请愿表的列: Petition Table

这些是我的PetitionSignature表的列: PetitionSignature Table

所以这就是发生的事情。我在调试模式下运行集成测试并测试它。我毫不费力地给我的Petition对象加水,并将它传递给PetitionSignatureProvider类中的这个方法。就在这发生的时候: Exception Time!

当然,可以进行此转换。在接受PetitionId的提供程序中创建另一个方法,转换就可以了。这让我相信问题在于我的映射,如上所示。

有什么想法吗?

3 个答案:

答案 0 :(得分:4)

条件查询的结果是一个通用列表,它返回一个实现IList的对象,因此您不能将其强制转换为通用列表。但是,您可以使用IEnumerable上的扩展方法将其转换为通用列表。以下代码应该有效:

public IList<PetitionSignature> GetByPetition(Petition p)
{
    return _session.CreateCriteria(typeof(PetitionSignature))
        .Add(Restrictions.Eq("Petition", p))
        .AddOrder(Order.Desc("Id"))
        .List()
        .Cast<PetitionSignature>()
        .OrderBy(sig => sig.Date)
        .ToList();
}

但是你已经拥有了Petition个对象。如果通过相同的会话通过NHibernate获取此对象,那么您只需编写:

public IList<PetitionSignature> GetByPetition(Petition p)
{
    return p.Signatures.OrderBy(sig => sig.Date).ToList();
}

甚至更好,你根本不需要一个方法。只需写下

p.Signatures.OrderBy(sig => sig.Date)

每当您需要按日期订购的特定请愿书的签名时。除此之外,我还有一些关于您的代码的建议:

  • 映射文件时出错。包中的<key>元素应该引用PetitionSignature表的外键字段。它应该是:<key column="Petition" />

  • 如果您的NHibernate版本不太旧,我会使用新的QueryOver api或NHibernate.Linq。这些都是使用lambda表达式而不是魔术字符串的类型安全查询API。

  • 我认为你想使用<set>代替<bag>。有关套装和行李的更多信息,请参阅this stackoverflow question

答案 1 :(得分:1)

System.Collections.ArrayList 实现通用接口System.Collections.Generic.IList<T>,而非通用接口System.Collections.IList。这些不应该是兼容的,除非C#做了一些我在这种情况下不知道的魔法。

如果NHibernate有一个返回泛型集合的API,您应该使用它来检索结果。否则,您可以使用IEnumerable.OfType()IEnumerable.Cast()

如果这在另一种方法中有效,则可能是NHibernate在导航使用实体类中的泛型类型的关联时返回泛型集合,但在使用ICriteria API查询时返回非泛型集合实体清单。该文档还暗示较新的QueryOver API也使用泛型。

答案 2 :(得分:1)

在条件中使用.List<PetitionSignature>()代替.List()。这将返回您期望的通用集合,而无需演员表。

现在,一个映射错误,阻止您以更简单的方式执行此操作:

<bag name="Signatures" cascade="all-delete-orphan" inverse="true">
  <key column="Petition"/> <!-- This is the FK -->
  <one-to-many class="PetitionSignature"/>
</bag>

有了这个,你可以使用petition.Signatures,不需要Criteria查询。