How to create nullable one-to-many relationship in Entity Framwork 6 code first

c# entity-framework entity-framework-6

Question

I am building an application using EF 6.1 code first. The entity model contains the following classes:

public enum UnitSystem {
    English,
    Metric
}

public enum UnitTypes {
    Volume,
    Weight,
    Other
}

public class Unit {

    [DatabaseGenerated( DatabaseGeneratedOption.Identity ), Key]
    public int UnitId { get; set; }

    [Required, MaxLength( 128 ), Index( IsUnique = true )]
    public string UnitName { get; set; }

    [Required]
    public UnitSystem UnitSystem { get; set; }

    [Required]
    public UnitTypes UnitType { get; set; }

    public virtual ICollection<Item> Items { get; set; }
}

public class Item {

    [DatabaseGenerated( DatabaseGeneratedOption.Identity ), Key]
    public int ItemId { get; set; }

    [Required, MaxLength( 128 ), Index( IsUnique = true )]
    public string ItemName { get; set; 

    [Required]
    public int UnitId { get; set; }

    [ForeignKey( "UnitId" )]
    public virtual Unit Units { get; set; }

    /// Other unimportant properties
}

public class UnitConversion {

    [Required, Key, Column( Order = 0 )]
    public int FromUnitId { get; set; }

    [ForeignKey( "FromUnitId" )]
    public virtual Unit FromUnit { get; set; }

    [Required, Key, Column( Order = 1)]
    public int ToUnitId { get; set; }

    [ForeignKey( "ToUnitId" )]
    public virtual Unit ToUnit { get; set; }

    [Key, Column( Order = 2 )]
    public int? ItemId { get; set; }

    public virtual Item Item { get; set; }

    [Required]
    public double ConversionFactor { get; set; }
}

When EF builds the database, I get the "Introducing FOREIGN KEY CONSTRAINT" message. I need the ItemId property to be nullable, and if it's not null, I need it to be a foreign key into the Items table.

What's the right way to create this relationship to avoid the cascading deletes error?

Edit

I'm no longer getting the error on the ItemId column; now I'm getting it for either the FromUnitId or ToUnitId columns, or both.

I've added navigation properties to the Unit class:

[ForeignKey("FromUnitId")]
public virtual ICollection<UnitConversion> FromConversions { get; set; }

[ForeignKey("ToUnitId")]
public virtual ICollection<UnitConversion> ToConversions { get; set; }

And this is the full text of the error message that I get:

Introducing FOREIGN KEY constraint 'FK_dbo.UnitConversions_dbo.Units_ToUnitId' on table 'UnitConversions' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.

There is supposed to be a zero-or-one to many relationship between the UnitConversions table and the Units table. When I try to create the call to modelBuiloder.Entity<UnitConversions>().WillCascadeOnDelete(false), IntelliSense does not show the WillCascadeOnDelete method, and the code won't compile.

1
-1
5/6/2016 3:20:24 PM

Accepted Answer

First I would recommend doing a quick read of entityframeworktutorial to make sure you have your keys set up as suggested. For a 1 to 1 relationship it is a little tricky; basically the primary key of the 'Child' is a foreign key to the 'Parent'.

Alternatively you can use fluent API in the Data Context and do something like this to make sure that the relationship and cascade go as expected:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<Student>().HasOptional(e => e.StudentAddress)
            .WithRequired(m => m.Student);

        modelBuilder.Entity<StudentAddress>.WillCascadeOnDelete(false);

    }

This says a Student has an optional StudentAddress, and the StudentAddress has an required Student, and when the StudentAddress is deleted the Student is not.

0
5/5/2016 8:08:33 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow