Question

The background

My model looks like the following: (writing fields instead of properties for simplicity)

public class Entity {
    public long Id;
    public string Name;
    public Entity Parent;
}

Essential FNH mapping

        Map(x => x.Name)
            .Not.Nullable()
            .UniqueKey("Child");

        References(x => x.Parent)
            .Cascade.None()
            .UniqueKey("Child");

SQL

create table `Entity` (Id BIGINT not null, Name VARCHAR(255) not null, Parent_id BIGINT, primary key (Id),unique (Name, Parent_id))

And that's fine. I don't want omonimities between children of the same entities (so two entities of different parent may have same name). By the way, bear in mind that Parent_id is nullable

What I need to do

I want to enforce a check before inserting a new entity into the DB. Instead of catching an exception I want to fire a query (but I think it reduces performance...) to check if an entity with same name and parent of newcoming exists in order to throw a decent exception. Despite performance, it's still a chance to learn something new about LINQ providers

In plain old SQL I would do

SELECT Id FROM entity WHERE Name = ? AND Parent_id = ?

and this correctly supports NULL ids

What I tried (and failed, otherwise I wouldn't be here)

var exInput = (from Entity entity in entityRepository.Query()
    where entity.Name.ToLowerInvariant() == _newEntity.Name.ToLowerInvariant()
        && entity.Parent.Equals(_newEntity.Parent)
    select new { ParentName = entity.Parent != null ? entity.Parent.Name : null }).FirstOrDefault();

I thought NHibernate could be smart enough to accept a null value as _newEntity.Parent and also smart enough to read entity.Parent.Equals as an expression instead of a method call (which fails in case of null).

Anyway that's not the problem

The error

System.NotSupportedException: Boolean Equals(System.Object)

I know NHibernate LINQ is not a full LINQ provider and doesn't support all methods Entity Framework supports. So I could expect that. Obviously, I can workaround by first selecting entity by name and then check if both parents are null or if they Equals() (I overloaded Equals to check Id)

The question

Given that I want NHibernate to generate SQL as closest as possible to the above WHERE clause, what should I do? Is there a different LINQ syntax to use or should I extend the LINQ provider?

I was thinking about extending LINQ provider, for which I have found some documentation. It is my opinion that if the operands of comparison are of the same identity we can simply match their ID (and if one of the entities is null generate NULL identity in HQL). In this case, did anyone try an implementation to share?

Was it helpful?

Solution

Don't use Equals in the query, just use entity.Parent == _newEntity.Parent.

Your Linq query also has a few additonal differences to the SQL you want to get. Why don't you simply use the following query?

var result = (from Entity entity in entityRepository.Query()
              where entity.Name == _newEntity.Name && entity.Parent == _newEntity.Parent
              select entity.Id).ToArray();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top