When declaring relationship is not necessary in Entity Framework 6?

c# ef-fluent-api entity-framework entity-framework-6 navigation-properties

Question

In EF6 we have two ways to declare relationship between two tables:

  • Annotations Attributes

  • Fluent API

Today (by accident) I removed one relationship between two tables and everything kept working well. I was very surprised because there was no way EF would know how those two tables are connected.

Tables look like that:

[Table("item")]
public class Item
{
    public Item()
    {
        ItemNotes = new HashSet<ItemNote>();
    }
    [Key]
    [Column("itemID", TypeName = "int")]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int itemID { get; set; }

    public ICollection<ItemNote> ItemNotes { get; set; }
}

[Table("itemNotes")]
public class ItemNote
{
    [Key]
    [Column("id", TypeName = "int")]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    [Column("itemID", TypeName = "int")]
    public int ItemId { get; set; }
    [Column("note", TypeName = "varchar")]
    [MaxLength(255)]
    public string Note { get; set; }
}    

Fluent API:

public class MyContext : DbContext
{
    public MyContext()
        : base("name=MyContext")
    {
    }
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        Database.SetInitializer<MyContext>(null);

        //I removed this relationship:
        //modelBuilder.Entity<Item>().HasMany(i => i.ItemNotes).WithRequired().HasForeignKey(i => i.ItemId);

        base.OnModelCreating(modelBuilder);
    }    
}

Here is the test I made: It's an integration test, that connects to the real database, gets items with notes and tests the EF:

    [TestCase]
    public void QueryItemWithItemNotesTest()
    {
        FniContext fniContext = new FniContext();

        int itemId = fniContext.Database.SqlQuery<int>("SELECT TOP(1) itemId FROM item WHERE itemId IN (SELECT itemId FROM dbo.itemNotes)").FirstOrDefault();
        var item = fniContext.Items.AsNoTracking()
            .Include(i => i.ItemNotes)
            .Where(i => i.itemID == itemId).FirstOrDefault();

        Assert.IsNotNull(item);
        Assert.Greater(item.ItemNotes.Count, 0);
    } 

It passes! It loads all notes! How come?!

I kept investigating and it turned out that in case of 1:many relationship I totally don't have to have any relationship in the code. The only time I need it is with 1:1 relationship. Am I'm missing something? Most of relationships are 1:many, so does it mean Fluent API is used for 1:1 most of the time?

1
1
3/8/2018 8:47:24 PM

Accepted Answer

Entity Framework has some conventions that you do not need to define explicitly.

From https://msdn.microsoft.com/en-us/library/jj679962(v=vs.113).aspx#Anchor_2

In addition to navigation properties, we recommend that you include foreign key properties on the types that represent dependent objects. Any property with the same data type as the principal primary key property and with a name that follows one of the following formats represents a foreign key for the relationship: '<navigation property name><principal primary key property name>', '<principal class name><primary key property name>', or '<principal primary key property name>'. If multiple matches are found then precedence is given in the order listed above. Foreign key detection is not case sensitive. When a foreign key property is detected, Code First infers the multiplicity of the relationship based on the nullability of the foreign key. If the property is nullable then the relationship is registered as optional; otherwise the relationship is registered as required.

2
3/8/2018 10:41:07 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