Как эффективно отфильтровать коллекцию дочерних объектов по свойству с помощью NHibernate - PullRequest
1 голос
/ 23 июня 2010

Я безуспешно пытался отфильтровать коллекцию дочерних объектов в течение нескольких часов, как и, наконец, поднял руки!Я новичок в NHibernate и надеялся на пару указателей на это.Я пробовал различные ICriteria и т. Д. Без удачи.Я просто не понимаю.

У меня есть родительский объект 'Post' с коллекцией дочерних объектов 'Comment'.Коллекция отображается в виде набора с инверсией на стороне комментария.

Я пытаюсь вернуть только комментарии со значением перечисления статуса 'Comment.Approved'

части классов сущностей выглядят следующим образом:

public class Post
{
    public virtual Guid Id { get; protected set; }
    private ICollection<Comment> _comments;
    public virtual ICollection<Comment> Comments
    {
        get { return _comments; }
        protected set { _comments = value; }
    }
}

public class Comment
{
    public virtual Guid Id { get; protected set; }
    public virtual Post Post { get; set; }
    public virtual CommentStatus Status { get; set; }

 }

Мой поисковый код выглядит сейчас так:

var Id = __SomeGuidHere__;
var post = _session
            .CreateCriteria<Post>()
            .Add(Restrictions.Eq("Id", Id))
            .UniqueResult<Post>();

var comments = _session.CreateFilter(post.Comments, "where Status = :status").SetParameter("status", CommentStatus.Approved).List<Comment>();

Хотя это работает, SQL не кажется очень эффективнымЯ ожидал, что смогу перевести следующий SQL-код во что-то похожее в HQL или в ICriteria некоторого вида:

SELECT * FROM posts p LEFT JOIN comments c ON p.PostId = c.PostId AND c.Status = 0 WHERE p.PostId = '66a2bf13-1330-4414-ac8a-9d9b00ea0705';

Здесь я рассмотрел различные ответы, относящиеся к этому типу запроса, ипохоже, что ни один из них не рассматривает этот конкретный сценарий.

Возможно, здесь что-то очень простое, что я упускаю, но сейчас я слишком устал, чтобы это увидеть.Мы надеемся, что кто-то лучше с NHibernate может указать мне правильное направление.

Спасибо за ваше время.

Редактировать: Все еще борются с этим, некоторые из ответов здесьхорошо, что я начинаю думать, что моя сущность поста должна быть переосмыслена для выполнения самой фильтрации, или что мне следует реализовать ViewModel для фильтрации комментариев, которые я хочу.Однако этот вопрос все еще остается, даже если только с академической точки зрения.

Я обновил выбор до HQL и попробовал:

var post = _session
            .CreateQuery("select p from Post as p left join fetch p.Comments as c where p.Id = :id and c.Id in (select ac from p.Comments ac where ac.Status = :status)")
            .SetParameter("id", Id)
            .SetParameter("status", CommentStatus.Approved)
            .UniqueResult<Post>();

Это работает, пока сообщение имеет утвержденныйкомментарий, в противном случае я не получаю сообщения из-за SQL, сгенерированного с использованием AND в предложении where.

Кто-нибудь?Я в тупике!

Обновление: Спасибо всем, кто ответил, это было полезно и заставило меня пересмотреть части моей модели.Поскольку наиболее часто используемые комментарии в качестве дочерних элементов сообщения используются при просмотре сообщения, в этом сценарии должны просматриваться только утвержденные комментарии.В большинстве других сценариев, которые я могу себе представить, комментарии будут доступны напрямую и будут отфильтрованы по статусу, что, конечно, прямо вперед.

Я обновил свои отображения, чтобы отфильтровать все сообщения> загрузка комментариев, чтобы загружать только утвержденные сообщения, как показано(в FluentNHibernate):

 HasMany(x => x.Comments).Where(x => x.Status == CommentStatus.Approved)
            .AsSet()
            .Inverse()
            .KeyColumn("PostId")
            .ForeignKeyConstraintName("PostComments")
            .OrderBy("CreatedOn")
            .Cascade.AllDeleteOrphan();

Хотелось бы пометить все как ответ, так как все помогло мне решить эту проблему, но Питер первым указал, что я могу думать о модели неправильно.

Спасибо всем.

Ответы [ 3 ]

0 голосов
/ 23 июня 2010

Я думаю, что это будет работать нормально:

var comments =
_session.CreateCriteria<Comment>
.CreateAlias("Post", "post")
.Add (Restriction.Eq("Status", status))
.Add (Restriction.Eq("post.Id", Id)).List();

Я не уверен, если вам нужна часть .CreateAlias ​​(если она вам не нужна, возможно, Post.Id будет работать тоже - но яне уверен).

0 голосов
/ 23 июня 2010

Я бы решил эту проблему, используя метод расширения для IEnumerable<Comment>:

public static IEnumerable<Comment> FilterByStatus(this IEnumerable<Comment> comments, CommentStatus status)
{
    return comments.Where(x => x.Status == status);
}

Пусть NHibernate вернет всю коллекцию, а затем отфильтрует ее при необходимости.

0 голосов
/ 23 июня 2010

По моему мнению, SQL идеально подходит для того, что вы описываете.

База данных имеет собственный оптимизатор и будет знать, что делать, чтобы эффективно доставлять ваши данные к вашему порогу.

...