Search code examples
c#eventsnhibernatefluent-nhibernate

Fluent NHibernate - do not return entity if one of its dependencies do not exists


Lets assume that I have table "Cells", table "Divisions" and joining table between them. Moreover, I can't map table "Cells", because I have "CellsView" which I have to map (it can show cells dependent on current user permissions)

Next.. there can be a situation when Division is assigned to one cell but current user wont see that cell if he want to list them. While retrieving list of Divisions, our user gets exception that says that expecting Cell with ID "1" does not exist. (ID is correct and Cell exists but our View does not allow to show that cell)

How can I prevent Divisions list from throwing an exception (lazy loading is enabled) **and from showing division which would throw that exception **?

I've tried to null current entity on OnPreLoad event and OnPostLoad event if my Cell entity cannot be resolved but it doesn't work. All divisions entities are returned and while reading them fluent tries to resolve Cell and throws exception.

That CellsView connection is used in many places inside application, so generic solution like this one with PostLoad events would be great to deal with it globally.


Solution

  • I am not using Fluent but if it duplicates what .hbm.xml mappings can do, you should be able to define and apply a filter on your collection. This should allow you to handle your case.

    Filters allows to define some parameterized restriction on the elements of an entity collection. You can parameterize and activate filters after session opening, where you should know who is your user.

    Indeed, filters can be defined outside of mappings, so even if Fluent does not handle them, you should still be able to use them.

    Example from Nhibernate reference documentation:

    ICollection<Cat> blackKittens = session.CreateFilter(
        pk.Kittens, "where this.Color = ?", Color.Black, NHibernateUtil.Enum(typeof(Color))
    ).List<Cat>();
    

    More details after comments:

    Filters should be able to navigate sub-entities too. But as your case is a bit wicked (foreign key is defined but foreign entity will not be found), you should test a non-nullable property of your sub-entity, but not its primary key. (Otherwise NHibenate will very likely simplify it by a test on parent foreign key.)

    "where this.Cell.SomeNonNullableProperty is not null"
    

    This would be translated to SQL and should be executed without exceptions, and would filter out your non-accessible divisions.

    By the way, filters may not be the answer for you, if all you do to get Division lists is explicitly querying them. (Not getting them through some over entities referencing them as a collection.) In such case, simply use above condition directly on your queries.

    For only addressing the exception, you may also tinker your mapping with the not-found="ignore|exception" option of many-to-one relations. But I am not sure it plays well with lazy-loading, I have never tried it. (And I do not know if this option is available with fluent.)