Configuring a read only navigation property as a constructor parameter

Viewed 138

I have the following models:

public class Session
{
    public string Id { get; set; }

    public IList<SessionWorkspace> Workspaces { get; } = new List<SessionWorkspace>();
}
public class SessionMeasurement
{
    public SessionMeasurement(Session session, string measurement)
    {
        Session = session;
        Measurement = measurement;
    }

    public string Id { get; set; }

    public Session Session { get; }
    public string Measurement { get; }
}

But I am struggling to configure them without getting an error. When I do this:

modelBuilder
    .Entity<Session>(entityBuilder =>
    {
        entityBuilder
            .HasMany(s => s.Workspaces)
            .WithOne(sw => sw.Session);
    });

modelBuilder.Entity<SessionWorkspace>(entityBuilder =>
{
    entityBuilder
        .Property(sw => sw.Session);
    entityBuilder
        .Property(sw => sw.Workspace);
});

I get the error:

System.InvalidOperationException: ''Session' cannot be used as a property on entity type 'SessionWorkspace' because it is configured as a navigation.'

But when I don't configure Session as a property like this:

modelBuilder
    .Entity<Session>(entityBuilder =>
    {
        entityBuilder
            .HasMany(s => s.Workspaces)
            .WithOne(sw => sw.Session);
    });

modelBuilder.Entity<SessionWorkspace>(entityBuilder =>
{
    entityBuilder
        .Property(sw => sw.Workspace);
});

I get this error:

System.InvalidOperationException: 'No suitable constructor was found for entity type 'SessionWorkspace'. The following constructors had parameters that could not be bound to properties of the entity type: cannot bind 'session' in 'SessionWorkspace(Session session, string workspace)'.'

So do I properly configure a readonly navigation property that is passed through the constructor?

1 Answers

Navigation properties are not "properties" by EF Core terminology, but "navigations". Hence you cannot use methods called Property to configure/access them. EF Core 5.0+ provides special method called Navigation for fluently configuring them, which however won't solve the original problem.

And the original problem is that navigation properties are not supported in constructors

  • EF Core cannot set navigation properties (such as Blog or Posts above) using a constructor.

So, remove the Property fluent call and just add a private parameterless constructor to your class to be used by EF Core when materializing it. e.g.


// for EFC
private SessionMeasurement() { }

// for public
public SessionMeasurement(Session session, string measurement)
{
    Session = session;
    Measurement = measurement;
}

Related