我在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" />
这些是我的请愿表的列:
这些是我的PetitionSignature表的列:
所以这就是发生的事情。我在调试模式下运行集成测试并测试它。我毫不费力地给我的Petition对象加水,并将它传递给PetitionSignatureProvider类中的这个方法。就在这发生的时候:
当然,可以进行此转换。在接受PetitionId的提供程序中创建另一个方法,转换就可以了。这让我相信问题在于我的映射,如上所示。
有什么想法吗?
答案 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查询。