1

I am using value objects as identities and would like to know how to best deal with nulls in EF core.

For example if I have an employee with an optional title (mr, mrs, etc):

public class Employee
  : Entity,
    IAggregateRoot
{
  public EmployeeTitleId TitleId { get; private set; }
  public EmployeeFirstName FirstName { get; private set; }
  public EmployeeSurname Surname { get; private set; }
   ...
}

I could check for nulls everywhere in my code e.g.

if (employee.TitleId == null) ...

or I could use a default e.g.

if (employee.TitleId.Equals(EmployeeTitleId.None)) ...

with the EmployeeTitleId implemented as follows:

public class EmployeeTitleId
  : Value<EmployeeTitleId>
{
  public static readonly EmployeeTitleId None = new EmployeeTitleId();

  protected EmployeeTitleId() { }

  public EmployeeTitleId(Guid value)
  {
    if (value == default)
      throw new ArgumentNullException(nameof(value), "Employee title id cannot be empty");

    Value = value;
  }

  public Guid Value { get; internal set; }

  public static implicit operator Guid(EmployeeTitleId self) => self.Value;

  public static implicit operator EmployeeTitleId(string value)
    => new EmployeeTitleId(Guid.Parse(value));

  public override string ToString() => Value.ToString();
}

I would prefer the second approach as it seems cleaner but I don't know if this is overkill. It would also require a bit more setup on the entity framework side e.g.:

builder.OwnsOne(_ => _.TitleId).Property(_ => _.Value)
 .HasColumnName("TitleId").HasConversion(v => v == default ? (Guid?) null : v, v => v ?? EmployeeTitleId.None);

Does this seem like a viable approach or should I just stick to checking for null? If so, is there a convention I could use in the entity type configurations so that I don't have to manually set each HasConversion?

Newm
  • 1,313
  • 3
  • 16
  • 29

1 Answers1

0

There is another way to filter the results globally. You can configure this in the OnModelCreating like:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    // code omitted for brevity

    modelBuilder.Entity<Employee>().HasQueryFilter(p => p.TitleId == null);
}
Cristian Szpisjak
  • 2,429
  • 2
  • 19
  • 32
  • Wouldnt this mean that when I query the Emaplyees DbSet only records with a null TitleId are returned? What I am trying to do is avoid null checks in my application layer code. – Newm Jun 26 '20 at 07:23
  • This is a global filter applied with each call to the database. The `null` check was an example but you can use this to retrieve only the data you need without having to make a check every single time. – Cristian Szpisjak Jun 26 '20 at 15:30
  • I am not trying to filter out records, I am trying to avoid if (xyz == null) checks in my code – Newm Jun 28 '20 at 14:47