Запросы на коллекцию строк с NHibernate - PullRequest
2 голосов
/ 17 марта 2009

У меня есть класс "Item", и у этого класса есть коллекция "Tags".

Item
    IList<string> Tags;

моя БД выглядит так:

Items
   Id

Tags
   ItemId
   TagName

Я пытаюсь получить все предметы, которые имеют теги "x" и "y". Как я могу сделать это с помощью NHibernate (желательно с критериями API)? Это вообще возможно?

Спасибо.

EDIT: я могу сделать это без сопоставления объекта Tag? Это не может быть 1 запрос. Что-то вроде

  1. var q = запрос, который будет возвращать все идентификаторы объектов, имеющих тег x или тег y ".

  2. var res = запрос, который вернет все элементы с идентификатором in (q.Execute ())

Ответы [ 3 ]

2 голосов
/ 09 марта 2010

Я недавно столкнулся с той же проблемой и действительно нигде не нашел хорошего решения для моей конкретной проблемы. В моем решении мне был нужен сопоставленный объект Tags, так как он был немного сложнее. Я опишу, что я сделал, если это кому-нибудь поможет. По сути это эквивалент следующего sql:

SELECT * 
FROM Items I 
WHERE 2 = (
    SELECT COUNT(DISTINCT TagName) 
    FROM Tags T 
    WHERE T.ItemId = I.ID) 
      AND (T.TagName = 'X' OR T.TagName = 'Y')
)



NHibernate.ICriteria criteria = session.CreateCriteria(typeof(Item),"I");

ICriterion tagCriteria = null;
foreach (string tag in tagNames) {
    ICriterion newCriteria = Expression.Eq("TagName", tag);
    if (tagCriteria == null) {
        tagCriteria = newCriteria;
    } else {
        tagCriteria = Expression.Or(tagCriteria, newCriteria);
    }
}
if (tagCriteria != null) {
    DetachedCriteria subCriteria = DetachedCriteria.For<Tags>("T");
    subCriteria.SetProjection(Projections.CountDistinct("TagName"))
        .Add(Expression.EqProperty("I.Id", "T.ItemId"))
        .Add(tagCriteria);
    criteria = criteria.Add(Subqueries.Eq(tagNames.Count,subCriteria ));
}
return criteria.List<Item>();
2 голосов
/ 17 марта 2009

Попробуйте что-то вроде этого:

session.CreateCriteria(typeof(Item))
    .CreateCriteria("Tags", global::NHibernate.SqlCommand.JoinType.InnerJoin)
    .Add(Expression.Eq("TagName", "x"))
    .Add(Expression.Eq("TagName", "y"))
    .List()

EDIT: Убедитесь, что у вас двунаправленная связь между Item и Tag. На беглом языке это будет выглядеть примерно так:

public class ItemMap : ClassMap<Item>
{
    public ItemMap()
    {
        ...
        HasMany(x => x.Tags).Inverse();
        ...
    }
}

public class TagMap : ClassMap<Tag>
{
    public TagMap()
    {
        ...
        References<Item>(x => x.Item);
        ...
    }
}
1 голос
/ 16 сентября 2009

Я думаю, что проблема, которую вы получаете, связана с этим: https://www.hibernate.org/117.html#A2 - то есть коллекции строк / компонентов не могут быть запрошены таким образом с помощью API критериев.

Я решил проблему с помощью HQL, как указано в связанном FAQ:

session.CreateQuery("from Item item "
    + "where :x in elements(item.Tags) and :y in elements(item.Tags)")
    .SetString("x", X)
    .SetString("y", Y);

Кажется, что работает как задумано.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...