2

I have a mapped class that has a ICollection property which is mapped as a Set (using by code mappings). Note that the collection contains strings and not another mapped entity. e.g.

public class Item
{
    public virtual ICollection<string> Facts { get; set; }  
}

public class ItemMapping
{
    public ItemMapping()
    {
        Set(x => x.Facts, m =>
        {
            m.Key(k => k.Column("ItemId"));
            m.Table("Facts");
        }, col => col.Element(m =>
        {
            m.Column("Description");
            m.Type(NHibernateUtil.String);
        }));
    }
}

This works and CRUD operations on Items with Facts works fine.

However, I want to QueryOver<> the Facts in the database (e.g. retrieve the count or first 20 facts or retrieve some random facts) but given there is no entity how do I do this? I don't want to introduce a Fact entity because the only property it would have would be a string.

Chet
  • 199
  • 10

2 Answers2

2

Well, my suggestion would be:

introduce entity. Even if it would have only one property. Later you can extend that (with Order, IsVisible). And if you will do that everywhere your framework will be built only from one-to-many and many-to-one relations among first citizens objects. That mean simple "framework generalization, reuse..."

But I see that you do not like it (please, at least try to re-think) - so there is the way:

NHibernate How do I query against an IList property?

Where I tried to show that (based on the documentation) we can use magical word ".elements":

17.1.4.1. Alias and property references

So the query which will touch the string elements in your case

Item item = null;
string fact = null;
var demos = session.QueryOver<Item>(() => item)
       .JoinAlias(i => i.Facts, () => fact)

        // instead of this
        // .Add(Restrictions.Eq("fact", "abc"))

        // we can use the .elements keyword
        .Where(Restrictions.Eq("fact.elements", "abc"))

        .List<Item>();

So, this way, you can get Items which do have some facts equal to "abc"

Community
  • 1
  • 1
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • I've accepted this answer as its probably the best way around it. Reason I didn't want to map it to an entity is because it goes against YAGNI / KISS principles in my view i.e. you can later extend it etc. So I ended up mapping it as it does give me additional QueryOver<>() flexibility/options.. – Chet Jan 19 '15 at 11:42
  • I could not for the life of me replicate this answer, even despite the simplest of code. I read somewhere else there may be a bug with aliasing in older NHib versions (< 4?). Anyway, I had to create a class to represent the string item and then could do my QueryOvers no problem. A bit sucks, but at least I have type safety. – ctrlplusb Jan 17 '16 at 09:14
1

non entities have to be queried by their entities and selected then. For example to get the first 20 facts:

string fact = null;
var first20facts = session.QueryOver<Item>()
    .JoinAlias(i => i.Facts, () => fact)
    .OrderBy(() => fact).Asc
    .Take(20)
    .Select(() => fact)
    .List<string>();

Alternativly you could also map a readonly entity for Fact just to query it.

Firo
  • 30,626
  • 4
  • 55
  • 94