简体   繁体   中英

EF CodeFirst bidirectional 1 : 0 or 1 relationship

I have 3 entities; Groups, Scopes, Vlans

What I'm trying to accomplish:

  • A Group can have many Scopes
  • A Group can have many Vlans
  • A Scope must have a Group
  • A Vlan must have a Group
  • A Scope can have a Vlan
  • A Vlan can have a Scope

So kind of a soft relationship between vlans and scopes.

When not setting vlan or scope as a requirement EF complains about not knowing the principal of the relationship, So how do I fix this soft one to one relationship?

My Models:

public class Group
{
    public Group()
    {
        Scopes = new HashSet<Scope>();
        Vlans = new HashSet<VLAN>();
    }
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public ICollection<VLAN> Vlans { get; set; } 
    public ICollection<Scope> Scopes { get; set; } 
}
public class Scope
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }     
    public virtual VLAN Vlan { get; set; }
    public virtual Group Group { get; set; }
}
public class VLAN
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public virtual Scope Scope { get; set; }
    [Required]
    public virtual Group Group { get; set; }
}

There is a similar problem on SO, related to bidirectional Zero-to-One relationships: Implementing Zero Or One to Zero Or One relationship in EF Code first by Fluent API

I've tried the same approach on your schema and it works. See my FluentAPI configuration below:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<VLAN>()
            .HasOptional(vlan => vlan.Scope)
            .WithOptionalPrincipal();

        modelBuilder.Entity<VLAN>()
            .HasRequired(vlan => vlan.Group);

        modelBuilder.Entity<Scope>()
            .HasOptional(scope => scope.Vlan)
            .WithOptionalPrincipal();

        modelBuilder.Entity<Scope>()
            .HasRequired(scope => scope.Group);

        modelBuilder.Entity<Group>()
            .HasMany(group => group.Scopes);
        modelBuilder.Entity<Group>()
            .HasMany(group => group.Vlans);

}

To be sure, that it suites your needs, see the generated SQL for VLANs and Scopes tables:

CREATE TABLE [dbo].[Scopes] (
[Id]       INT            IDENTITY (1, 1) NOT NULL,
[VLAN_Id]  INT            NULL,
[Group_Id] INT            NOT NULL,
CONSTRAINT [PK_dbo.Scopes] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_dbo.Scopes_dbo.VLANs_VLAN_Id] FOREIGN KEY ([VLAN_Id]) REFERENCES [dbo].[VLANs] ([Id]),
CONSTRAINT [FK_dbo.Scopes_dbo.Groups_Group_Id] FOREIGN KEY ([Group_Id]) REFERENCES [dbo].[Groups] ([Id]) ON DELETE CASCADE);

CREATE TABLE [dbo].[VLANs] (
[Id]       INT            IDENTITY (1, 1) NOT NULL,
[Scope_Id] INT            NULL,
[Group_Id] INT            NOT NULL,
CONSTRAINT [PK_dbo.VLANs] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_dbo.VLANs_dbo.Scopes_Scope_Id] FOREIGN KEY ([Scope_Id]) REFERENCES [dbo].[Scopes] ([Id]),
CONSTRAINT [FK_dbo.VLANs_dbo.Groups_Group_Id] FOREIGN KEY ([Group_Id]) REFERENCES [dbo].[Groups] ([Id]) ON DELETE CASCADE);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM