仅获取只读实体的最新条目的限制集合

3

用户实体可能会有数千个用户操作。有时,我不想检索(对于只读实体)所有操作,而是只想检索“最近的10个或未完成的”。

public class SimpleForm
{
    public class User : EntityBase
    {
        //  ...

        private ISet<UserOperation> _recentOperations = new HashedSet<UserOperation>();
        public virtual ISet<UserOperation> RecentOperations { get { return _recentOperations; } set { _recentOperations = value; } }
    }
}

那我该怎么指定它呢?我认为我可以使用映射覆盖来实现?
我知道可以用单独的查询来完成这个任务,但是实体映射是否也能做到呢?
另外,我想知道是否有可能对非只读实体进行类似操作集合的修改?
更新:我尝试使用
DateTime dateTime = (DateTime.UtcNow - TimeSpan.FromDays(15));
mapping.HasMany(x => x.RecentOperations)
       .Where(x => x.EndedAt == null || x.EndedAt < dateTime);

但是它显示“无法将表达式转换为SQL”。

我用以下内容进行了替换

mapping.HasMany(x => x.RecentOperations)
                .Where(x => x.EndedAt == null);

现在它会在内部引发空引用异常

在FluentNHibernate.Utils.ExpressionToSql.Convert(Object value)中, FluentNHibernate.Utils.ExpressionToSql.Convert(ConstantExpression expression), 以及FluentNHibernate.Utils.ExpressionToSql.Convert[T](Expression`1 expression, UnaryExpression body)中。


我不是很确定你的问题,但你需要在你的DateTime字段上使用OrderByDescending,然后使用Enumerable.Take(10)来获取最近的10条记录。 - Habib
@Habib 但是有没有可能以这种方式映射实体,以便我只需使用Session.Get<SimpleForm.User>(id)? - Vlad
我不确定是否可以完成,我也会在这里等待答案。 - Habib
在映射中添加了我尝试使用Where子句的代码。 - Vlad
1个回答

1
有两种常见的方法来过滤映射集合。 第一种是有点死板、固定的,在一个映射中定义了where = ""子句: 第二种,也许在这种情况下真正适用的是动态版本,称为filter:

NHibernate 添加了预定义筛选条件并将这些筛选器附加到类和集合级别的功能。筛选条件是定义约束子句的能力,与现有类和各种集合元素上可用的“where”属性非常相似。除了这些筛选条件可以是带参数的。然后应用程序可以在运行时决定是否启用给定的过滤器以及它们的参数值。过滤器可以像数据库视图一样使用,但在应用程序中进行参数化....

在流畅的实现中,会像这样:
public class RecentFilter : FilterDefinition
{
    public RecentFilter()
    {
        WithName("RecentFilter")
            .WithCondition("( :EndedAtDate IS NULL OR EndedAt < :EndedAtDate )")
            .AddParameter("EndedAtDate",NHibernate.NHibernateUtil.DateTime);
    }
}

这是一个过滤器,在流畅映射中使用如下:
mapping
   .HasMany(x => x.RecentOperations)
   ...
   .ApplyFilter<RecentFilter>();

在运行时,我们可以在ISession级别上打开/关闭过滤器:
session.EnableFilter("RecentFilter")
       .SetParameter("EndedAtDate",DateTime.Now.AddDays(-15));

另请参阅:


当我调用EnableFilter()时,为什么会抛出“No such filter configured”? - Vlad
检查过滤器是否已配置...稍后我会回来展示更多内容...请关注我的链接... - Radim Köhler
已经解决了这个问题。但是我有两个实体:用户和朋友。用户(简化的用户实体,同一张表)。每个用户都有一个好友列表。我需要创建两个单独的过滤器,因为我想要加载较少天数的朋友操作,并且我只能按会话指定过滤器。还是有其他方法吗? - Vlad
首先抱歉回复晚了,我不在附近... 你应该尝试使用过滤器。简而言之:您可以为每个集合或每个类声明更多的过滤器。它们有不同的名称。然后,您可以决定应用其中哪些。甚至在一个会话中,一个类内部可以有两个过滤器。甚至更多... 您可以双重映射集合...但其中一个应该是只读的。然后,一个集合可以使用一个过滤器,而另一个集合可以使用第二个过滤器。不要忘记仅使用一个可写集合。请尝试一下,最终您会喜欢它的;) 祝NHibernate好运。 - Radim Köhler
顺便问一下,你能解释一下为什么我的Where()条件不起作用吗?请看问题。 - Vlad
是的,问题可能与以下事实有关:Where 可以包含:1)简单的布尔表达式或2)SQL 字符串。但在您的情况下,它既不是 2)SQL 字符串,也不是 简单 的布尔表达式。换句话说:将您的 C# 代码转换为 SQL 表达式,Where 就会起作用;)NHibernate 很强大;) - Radim Köhler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接