Jack
Jack

Reputation: 15872

Entityframework with an existing database - navigation properties not working

I have a set of Entities:

public class Board : EntityBase
{
    public ICollection<Slot> Slots { get; set; }
}

public class Slot : EntityBase
{        
    public ICollection<Card> Cards { get; set; }

    public string Header { get; set; }

    public int BoardId { get; set; }
}

public class Card : EntityBase
{        
    public string Description { get; set; }

    public string Title { get; set; }

    public int SlotId { get; set; }
}

And corresponding database tables:

CREATE TABLE Boards
(
    Id INT PRIMARY KEY,
    UserId INT NOT NULL,
    CONSTRAINT FK_Users_UserId FOREIGN KEY (UserId)
    REFERENCES Users(Id)
)

CREATE TABLE Slots
(
    Id INT PRIMARY KEY,
    Header NVARCHAR(MAX),
    BoardId INT NOT NULL,
    CONSTRAINT FK_Slots_BoardId FOREIGN KEY (BoardId)
    REFERENCES Boards(Id)
)

CREATE TABLE Cards
(
    Id INT PRIMARY KEY,
    Title NVARCHAR(MAX),
    Description NVARCHAR(MAX),
    SlotId INT NOT NULL,
    CONSTRAINT FK_Cards_SlotId FOREIGN KEY (SlotId)
    REFERENCES Slots(Id)
)

When attempting retrieving and instantiate a 'Board' from the database it's not populating the 'Slots' property. It seems that Entity framework is unable to recognise that there's a foreign key constraint. My understanding is that if the properties are not virtual they will be eager loaded, please correct me if i'm wrong.

Is there something that I'm missing / need to setup to make navigation properties work?

The calling code:

Context.Boards.Find(id);

My DbContext:

public class SampleContext : DbContext, IUnitOfWork
{
    public SampleContext() : base("name=SampleApplication") { }

    public void Save()
    {
        SaveChanges();
    }

    public DbSet<Board> Boards { get; set; }
    public DbSet<Card> Cards { get; set; }
    public DbSet<Slot> Slots { get; set; }
}

I have made the navigation properties virtual and loaded as follows, this is now working:

public Board GetBoard(int id)
{            
    var board = Context.Boards.Find(id);

    Context.Entry(board)
        .Collection(b => b.Slots)
        .Load();

    return board;
}

Upvotes: 1

Views: 68

Answers (2)

mrsargent
mrsargent

Reputation: 2442

Eager loading does not happen automatically like lazy loading does when you include the virtual keyword. You will need to use the Include() method

so something like

var graph = context.Boards.Include("Slots");
foreach(var board in graph)
{
   Console.Writeline("Slot value {0}",board.Slots);
}

Upvotes: 1

astef
astef

Reputation: 9488

You must make navigation properties virtual for EF proxy to be able to override it.

And you're wrong about non-virtual properties to be eager loaded. They do not. You must load them explicitly with Include methods. Read here about it: https://msdn.microsoft.com/en-us/data/jj574232.aspx

Upvotes: 1

Related Questions