D.R.
D.R.

Reputation: 21194

Zero-or-one relationship in EF Core

I have a somewhat special scenario of a Zero-or-one relationship in EF Core which cannot be easily modeled by the default (as described, e.g.,in EF Core One to One or Zero Relationship).

I've got multiple entities with a 0-1 relationship to a "Match" entity. Multiple instances can reference the same "Match" entity (which is why I can't put the foreign key into the "Match" table, which seems to be the recommended way of modeling a 0-1 relationship).

How to define the relationship from one of the entities to 0-1 "Match" entities? Do I have to create a Match().HasMany(someKindOfBaseClassOfEntities) instead? Is there a better way?

Upvotes: 0

Views: 1272

Answers (1)

Gert Arnold
Gert Arnold

Reputation: 109109

You can configure this by using HasOne, which allows a 1:0..1 relationship. Just showing one way of doing this without repeating too much mapping code:

Classes:

class Match
{
    public int ID { get; set; }
    public string Name { get; set; }
}

abstract class HasMatchBase
{
    public int ID { get; set; }
    public string Name { get; set; }
    public int? MatchID { get; set; }
    public Match Match { get; set; }
}

class A : HasMatchBase
{
    public string Code { get; set; } // Just an example
}

class B : HasMatchBase { }

Mapping configuration:

abstract class HasMatchBaseConfig<T> : IEntityTypeConfiguration<T>
    where T : HasMatchBase
{
    public void Configure(EntityTypeBuilder<T> builder)
    {
        builder.Property(b => b.Name).HasMaxLength(200);
        builder.HasOne(b => b.Match).WithOne().HasForeignKey<T>(b => b.MatchID);

        ConfigureMatchOwner(builder);
    }
    
    public abstract void ConfigureMatchOwner(EntityTypeBuilder<T> builder);
}

class AConfig : HasMatchBaseConfig<A> 
{ 
    public override void ConfigureMatchOwner(EntityTypeBuilder<A> builder)
    {
        builder.Property(a => a.Code).HasColumnType("CHAR").HasMaxLength(3);
        ... // Further A-specific mapping
    }
}

class BConfig : HasMatchBaseConfig<B>
{
    public override void ConfigureMatchOwner(EntityTypeBuilder<B> builder)
    {
        ... // B-specific mapping. 
    }
}

The type of HasMatchBase.MatchID determines whether the association is required or optional. In this case it's a nullable int, turning the association into Match being optional.

Upvotes: 2

Related Questions