0

I am trying to construct a query that will allow me to add an expression that will return only contacts that are/are not associated with a person.

The base IQueryable looks like this ... 

    internal static IQueryable<OrganizationContact> GetOrganizationContactQuery(IFDBCtx ctx)
    { 
        var query = from rContact in ctx.Contacts.Where(e => e.institution_id.HasValue)

                    join rPerson in ctx.People
                        on rContact.person_id equals rPerson.person_id into peopleGroup
                        from person in peopleGroup.DefaultIfEmpty()

                    select new BLL.OrganizationContact
                    {
                        ID           = rContact.contact_association_id, 
                        Title        = rContact.contact_title,
                        Notes        = rContact.notes,
                        CreatedBy    = rContact.created_by,
                        CreatedDate  = rContact.created_date,
                        UpdatedBy    = rContact.updated_by,
                        UpdatedDate  = rContact.updated_date,
                        ContactName  = (person == null) ? null : person.name,
                        Person       = (person == null) ? null : new BLL.Person { ID = person.person_id, Name = person.name }
                    }

        return query;
    }

This, however throws the exception ...

Unable to create a null constant value of type 'BLL.Person'. Only entity types, enumeration types or primitive types are supported in this context.

When I remove the person == null evaluation from the Person assignment the exception goes away ...

internal static IQueryable<OrganizationContact> GetOrganizationContactQuery(dbContext ctx)
{ 
    var query = from rContact in ctx.Contacts.Where(e => e.institution_id.HasValue)

                join rPerson in ctx.People
                    on rContact.person_id equals rPerson.person_id into peopleGroup
                    from person in peopleGroup.DefaultIfEmpty()

                select new BLL.OrganizationContact
                {
                    ID           = rContact.contact_association_id, 
                    Title        = rContact.contact_title,
                    Notes        = rContact.notes,
                    CreatedBy    = rContact.created_by,
                    CreatedDate  = rContact.created_date,
                    UpdatedBy    = rContact.updated_by,
                    UpdatedDate  = rContact.updated_date,
                    ContactName  = (person == null) ? null : person.name,
                    Person       = new BLL.Person { ID = person.person_id, Name = person.name }
                }

    return query;
}

But now I am left with another problem. When I attempt to evaluate to see if the Person is set or not ...

var query = GetOrganizationContactQuery(dbContext);
    query = query.Where(e=>Person == null);

I get another exception ...

The argument to DbIsNullExpression must refer to a primitive, enumeration or reference type.

In an effort to work around the issues I attempt to evaluate the ContactName instead (it's a primitive type after all).

var query = GetOrganizationContactQuery(dbContext);
    query = query.Where(e=>ContactName == null);

This does not throw an exception, but instead returns EVERY record in the table. As it turns out, the ternary expression, (person == null), appears to ALWAYS evaluates to NULL, even when the Name of the Person object property is correctly set! Here's an example of this output. You can see that the Person object was correctly set, but the ContactName is not present (properties with NULL values are not included in the JSON).

{
    "ID": 2467,
    "Title": "CEO",
    "CreatedBy": "gstenstrom",
    "CreatedDate": "2019-05-21T17:37:18.997",
    "UpdatedBy": "gstenstrom",
    "UpdatedDate": "2019-05-21T17:37:18.997",
    "Person": {
        "ID": 2610,
        "Name": "John Jones",
    }
}

So I cannot evaluate the Person object property and I cannot set the ContactName ... I cannot filter out the contacts that do or do not have People associated with them!

This is a pretty basic query seemingly made difficult by Linq. Am I missing something?

Upon further research I have discovered that this works ...

internal static IQueryable<OrganizationContact> GetOrganizationContactQuery(dbContext ctx)
{ 
    var query = from rContact in ctx.Contacts.Where(e => e.institution_id.HasValue)

                join rPerson in ctx.People
                    on rContact.person_id equals rPerson.person_id into peopleGroup
                    from person in peopleGroup.DefaultIfEmpty()

                select new BLL.OrganizationContact
                {
                    ID           = rContact.contact_association_id, 
                    Title        = rContact.contact_title,
                    Notes        = rContact.notes,
                    CreatedBy    = rContact.created_by,
                    CreatedDate  = rContact.created_date,
                    UpdatedBy    = rContact.updated_by,
                    UpdatedDate  = rContact.updated_date,
                    ContactName  = person.name,
                    Person       = new BLL.Person { ID = person.person_id, Name = person.name }
                }

    return query;
}


var query = GetOrganizationContactQuery(dbContext);
    query = query.Where(e=>ContactName != null);

But this does not ...

internal static IQueryable<OrganizationContact> GetOrganizationContactQuery(dbContext ctx)
{ 
    var query = from rContact in ctx.Contacts.Where(e => e.institution_id.HasValue)

                join rPerson in ctx.People
                    on rContact.person_id equals rPerson.person_id into peopleGroup
                    from person in peopleGroup.DefaultIfEmpty()

                select new BLL.OrganizationContact
                {
                    ID           = rContact.contact_association_id, 
                    Title        = rContact.contact_title,
                    Notes        = rContact.notes,
                    CreatedBy    = rContact.created_by,
                    CreatedDate  = rContact.created_date,
                    UpdatedBy    = rContact.updated_by,
                    UpdatedDate  = rContact.updated_date,
                    ContactName  = (person.name == null) ? null : person.name,
                    Person       = new BLL.Person { ID = person.person_id, Name = person.name }
                }

    return query;
}

var query = GetOrganizationContactQuery(dbContext);
    query = query.Where(e=>ContactName != null);

I have been through countless SO postings but none seem to have answered my question or identified what the underlying issue may be. Could be ignorance on my part though ...

Rufus L
  • 36,127
  • 5
  • 30
  • 43
Gary O. Stenstrom
  • 2,284
  • 9
  • 38
  • 59
  • Most probably https://stackoverflow.com/questions/18929483/unable-to-create-a-constant-value-of-type-only-primitive-types-or-enumeration-ty contains the right answer. It may not seem so for now with all the classes/conditions/expressions, but if you try to reduce your code to the [MCVE] it should become clear. – Eugene Podskal Feb 25 '20 at 18:49
  • I think you are having a server versus client issue. EF attempts to translate your query into SQL, and in SQL you normally don't need to deal with `null`, SQL will just propagate nulls by default. Since you aren't bringing the query over to the client, when you add the `Where` to test for `null`, it is still trying to translate the entire query to SQL. If you intend to extend an `IQueryable`, it is best to stick with anonymous types and place a final `select` at the very end. – NetMage Feb 25 '20 at 18:55
  • 1
    I think you need to test for DBNull.Value not null. null in sql sever and null in C# are two different things. Try using DBNull.Value instead. – BillRuhl Feb 25 '20 at 19:50

0 Answers0