Entity Framework and relationships with 1: 0..n relationships, what to do when it is 0?

99 views Asked by At

In the application I support, there are times that associations can be null as the client has not submitted the data yet. I don't know of any other way to handle this other than doing a null check. The database is set in stone (other applications consume it also) It turns my code into an mess. I was wondering if there is a better way to go about doing this (this code is going into an anonymous type, but using a class makes no difference. I can't add a predicate checking for null, because if the bill exists that information needs to be returned regardless of if claim patient or claim do not exist yet. Here is a simplified version:

            var baseQuery = Context.Bills.AsNoTracking()
            .Select
            (
                bill => new
                {
                    bill.BillId,
                    bill.BillStatus,
                    patientId = bill.ClaimPatient != null ? bill.ClaimPatientId : null,
                    claimPatientId =  bill.ClaimPatient != null && bill.ClaimPatient.Claim != null ? bill.ClaimPatientId : null,
                    bill.UserNumber,
                }
            );

And this null checking can go on and on. I know there is probably a better way, and when I see it I will face plant because it will probably be something so simple and obvious that I missed.

2

There are 2 answers

1
Timothy Shields On

I've found extensions methods like the following are sometimes useful for dealing with this.

public static class Extensions
{
    public static U Maybe<T, U>(this T t, Func<U> f) where U : class
    {
        return t != null ? f() : null;
    }

    public static U Maybe<T, U>(this T t, Func<T, U> f) where U : class
    {
        return t != null ? f(t) : null;
    }

    public static U? MaybeNullable<T, U>(this T t, Func<U> f) where U : struct
    {
        return t != null ? f() : (U?)null;
    }

    public static U? MaybeNullable<T, U>(this T t, Func<T, U> f) where U : struct
    {
        return t != null ? f(t) : (U?)null;
    }
}

Some example usage follows.

bill.ClaimPatient.Maybe(() => bill.ClaimPatientId)
bill.ClaimPatient.Maybe(cp => cp.Id)

person.Maybe(p => p.Employer).Maybe(e => e.Address)
3
Gert Arnold On

Good news: SQL doesn't have this null reference concept. So you can reduce the checks (in this case) to a simple cast to int?.

var baseQuery = Context.Bills.AsNoTracking()
.Select
(
    bill => new
    {
        bill.BillId,
        bill.BillStatus,
        patientId = (int?)bill.ClaimPatientId,
        claimPatientId = (int?)bill.ClaimPatientId,
        ClaimPatient.UserNumber,
    }
);

The whole statement is translated into SQL. The first thing the CLR knows is the result set coming from the database. This set may contain null values, so you only have to make sure that the final result can contains int and null in one property.

Maybe for the second Id value you need bill.ClaimPatient.Claim != null ? bill.ClaimPatientId : null, but I consider that business logic, rather than a null safety check.