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?

2
  • Couldn't EmployeeTitleId be an enum with a default value (0 = None) in the database field? Commented Jun 27, 2020 at 12:39
  • The list of titles is maintained by the user, its not a fixed list Commented Jun 28, 2020 at 14:46

1 Answer 1

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);
}
Sign up to request clarification or add additional context in comments.

3 Comments

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.
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.
I am not trying to filter out records, I am trying to avoid if (xyz == null) checks in my code

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.