【问题标题】:NHibernate QueryOver query subclass from baseNHibernate QueryOver 从基础查询子类
【发布时间】:2014-02-01 12:15:31
【问题描述】:

我有以下物品:

public abstract class Event {
    public virtual Guid Id { get; set; }
    public virtual string Description { get; set; }
}

public class TeamEvent : Event {
    public virtual Guid Id { get; set; }
    public virtual Team Team { get; set; }
}

public class PersonEvent : Event {
    public virtual Guid Id { get; set; }
    public virtual Person  Person { get; set; }
}

public class Team {
    public virtual Guid Id { get; set; }
    public virtual string Name { get; set; }
}

public class Person {
    public virtual Guid Id { get; set; }
    public virtual string Forename { get; set; }
    public virtual string Surname { get; set; }
}

和映射:

    <discriminator column="Discriminator"
            not-null="true"
            type="System.String"/>

    <subclass
        name="TeamEvent"
        discriminator-value="TeamEvent">
        <many-to-one name="Team" column="TeamId"/>
    </subclass>

    <subclass
        name="PersonalEvent"
        discriminator-value="PersonalEvent">
        <many-to-one name="Person" column="PersonId"/>
    </subclass>
</class>
<class name="Person" table="Persons">
    <id name="Id">
        <generator class="assigned"/>
    </id>
    <property name="Forename"/>
    <property name="Surname"/>
</class>
<class name="Team" table="Teams">
    <id name="Id">
        <generator class="assigned"/>
    </id>
    <property name="TeamName"/>
</class>

我想做的是一个查询,该查询将在一个查询中获取所有事件,而不管基本类型如何,以填充 DTO,例如:

public class EventDTO {
   public virtual Guid EventId { get; set; }
   public virtual string EventDescription { get; set; }
   public virtual Guid PersonId { get; set; }
   public virtual string PersonForename { get; set; }
   public virtual string PersonSurname { get; set; }
   public virtual Guid TeamId { get; set; }
   public virtual string TeamName { get; set; }
}

如果是人员事件,则团队字段为空,反之亦然。

在 SQL 中,我会执行以下操作:

Select * from Events
left join Team on Events.TeamId = Team.Id
left join Person on Events.Person = Person.Id

我无法在 QueryOver 中执行此操作,因为 Events c# 对象没有团队/人员的属性。我可以这样做:

var events = session.QueryOver<Event>
               .Where ( /* insert my restrictions */ )
               .Future<Event>();

var teamEvents = session.QueryOver<TeamEvent>
               .Where ( /* insert my restrictions */ )
               .Future<TeamEvent>();
var personEvents = session.QueryOver<PersonEvent>
               .Where ( /* insert my restrictions */ )
               .Future<PersonEvent>();

/* union the results in memory */

从这些查询返回的数据量应该能够将结果合并到内存中。我的问题是真的有更优雅的方法吗?无需执行三个单独的查询。

我应该指出,这只是我为突出显示我的问题而输入的一个简单示例,因此上述代码示例中可能存在一些拼写错误等。在现实世界的问题中,系统的其他部分取决于映射,因此更改架构/映射/对象不是一种选择。

虽然我更喜欢使用查询,但我不介意使用条件或 hql,如果可以在那里以更简单的方式进行操作的话。此外,此查询最多只会返回 20 行经常访问并因此存储在二级缓存中的实体,因此如果它使代码简单,即使 N + 1 也不是主要问题。

我还应该指出三个查询一个不那么简单的原因是因为每个查询需要复制 10 个限制,并且还有几个其他事件子类。

感谢您的帮助。

【问题讨论】:

    标签: c# sql nhibernate queryover


    【解决方案1】:

    当我遇到这样的问题时,我会停止与 NH 对抗并创建数据库视图。我映射为mutable=false。这样我就不会因为分页或 where 子句以及在客户端合并多个集合而陷入混乱。

    不确定是否有比您想出的更好的方法(尤其是当您有想要展平的相关表格时)。正如您所说,您没有太多数据,那么在客户端上合并可能是最好的。

    【讨论】:

    • 我什至会说:请尝试想象how to fill the DTO using C# only... runtime objects。即使这将是一个问题。换句话说(我个人会说)所需的功能似乎设计得不好。如果可能的话,应该重新考虑一下,并重新决定:这是我们这里所拥有的继承吗?
    • 我最终通过在客户端上合并得到了最好的代码。
    【解决方案2】:

    您应该能够使其与 HQL 一起使用并编写如下条件:

    from Event where (..person event restrictions..) OR (..team event restrictions..)
    

    因为查询抽象基类将强制 nHibernate 进行左连接,即使您指定了派生属性,它们也是可访问的。因此,以简化形式,以下查询

    var personEvents = session
                        .CreateQuery("from Event where Person!=null")
                        .List<Event>();
    

    会给你PersonEvent 实体。

    所以你应该能够构建更简单的代码,但是你想在一个查询中加载不同的子类并立即处理它们真的感觉很奇怪。未来的查询似乎足够优雅,因为它们专注于小(单)块责任感——如果需要举办另一场活动,你会怎么做?添加另一个查询而不是一次又一次地修改一个主查询感觉更好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-27
      • 2020-11-12
      • 2011-12-06
      相关资源
      最近更新 更多