Search code examples
c#entity-framework-coreef-code-first

How to prevent EF from creating a foreign key?


I have two tables Tenant and Language. A Tenant has one property for a default language and a second property for a list of possible alternate languages (inclusive of the default language). The Language table is just a reference table of a list of all possible language options. It does not need to contain any information about any other table. After configuring EF as best as I know how, it creates a TenantId foreign key in the Language table.

What about my configuration is causing this and how can I stop it?

Tenant Configuration:

public class TenantConfiguration : EntityConfiguration<Tenant>
{
    public override void Configure(EntityTypeBuilder<Tenant> builder)
    {
        base.Configure(builder);

        builder.HasOne(tenant => tenant.RootFolder).WithMany().OnDelete(Microsoft.EntityFrameworkCore.DeleteBehavior.ClientCascade); //unsure
        builder.HasMany(tenant => tenant.Languages).WithOne().OnDelete(Microsoft.EntityFrameworkCore.DeleteBehavior.NoAction);
        builder.Property<Guid>("DefaultLanguageId");
        builder.HasOne(tenant => tenant.DefaultLanguage).WithMany().OnDelete(Microsoft.EntityFrameworkCore.DeleteBehavior.NoAction);
    }
}

Language Configuration:

public class LanguageConfiguration : EntityConfiguration<Language>
{
    public override void Configure(EntityTypeBuilder<Language> builder)
    {
        base.Configure(builder);
    }
}

Entity model:

public abstract class Entity
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public virtual Guid Id { get; set; }
    
    public virtual DateTime Created { get; set; }
    
    public virtual DateTime Updated { get; set; }
}

Tenant model:

[Table("Tenant")]
public class Tenant : Entity
{
    [Required]
    public virtual string Name { get; set; }
    
    [Required]
    public virtual Folder RootFolder { get; set; }

    [Required]
    public virtual IList<Language> Languages { get; set; }

    [Required]
    public virtual Language DefaultLanguage { get; set; }
}

Language model:

[Table("Language")]
public class Language : Entity
{
    [Required]
    public virtual string Name { get; set; }
}

Here is the generated, incorrect schema

Edit: I am expecting the schema to look something like this. The Tenant table will hold references to Id's in the Language table. Languages shouldn't know which Tenants reference them.


Solution

  • This happens because you create a property Languages as a list in the Tenant model. Lists in relational databases do not exist. You cannot have a attribute that contains multiple values. EF does the following: It looks at the IList<Language> Languages property. Then it goes to the Language model and adds a Foreign Key attribute linked to the Tenant model.

    After looking at your explanation it seems like you want to create a N:M relationship, since you want to link multiple languages to a Tenant. For this you'll need a Associative entity (junction table). This is because you are trying to establish a N:M (Multiple to Multiple) relationship between two tables.