Entity Framework Core does not create join for related entities

77 Views Asked by At

I've created a couple of entities (Code First), a User and a Configuration. A user can have multiple configurations and each configuration has a single user.

public class ConfigurationDataContext : DbContext
{
    public ConfigurationDataContext(DbContextOptions options) 
        : base(options) { }

    public DbSet<User> Users { get; init; }
    public DbSet<Configuration> Configurations { get; init; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        new User().OnModelCreating(modelBuilder);
        new Configuration().OnModelCreating(modelBuilder);
    }
}

public class User
{
    public ObjectId Id { get; set; }
    public string? GivenName { get; set; }
    public string? FamilyName { get; set; }
    public DateTime CreationDate { get; set; } = DateTime.Now;

    public ICollection<Configuration>? Configurations { get; init; }

    public void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>(e =>
        {
            e.HasIndex(new string[] { "FamilyName", "GivenName" });
            e.HasMany(e => e.Configurations).WithOne(e => e.Owner);
        });
    }
}

public class Configuration
{
    public ObjectId Id { get; set; }
    public ObjectId? OwnerId { get; set; }

    public User? Owner { get; set; }
    public DateTime CreationDate { get; set; } = DateTime.Now;

    public void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Configuration>(e =>
        {
            e.HasOne<User>("Owner").WithMany("Configurations")
             .HasForeignKey(c => c.Id).IsRequired();
        });
    }
}

However, when I attempt to retrieve the configuration data, I get the following exception:

Field 'Microsoft.EntityFrameworkCore.Query.TransparentIdentifierFactory+TransparentIdentifier`2[Configuration,User].Outer' is not defined for type 'Configuration'

To get my entity model:

using Microsoft.EntityFrameworkCore;
using MongoDB.Bson;
using MongoDB.Driver;

var connectionString = "mongodb://localhost:27017";
var databaseName = "Simple-Configuration-test";
var client = new MongoClient(connectionString);
var database = client.GetDatabase(databaseName);

var db = new ConfigurationDataContext(new DbContextOptionsBuilder()
                                        .UseMongoDB(client, databaseName).Options);

var user = new User() { GivenName = "test", FamilyName = "user" };

var existing = db.Users.FirstOrDefault(u => u.FamilyName == user.FamilyName && u.GivenName == user.GivenName);

if (existing == null)
{
    db.Users.Add(user);
    db.SaveChanges();
}
else 
    user = existing;

Console.WriteLine($"User = {user.GivenName} {user.FamilyName} Created at {user.CreationDate}");

var configuration = new Configuration { Owner = user, OwnerId = user.Id };

var existingConfig = db.Configurations.Include(c => c.Owner).FirstOrDefault(c => c.OwnerId == user.Id);

if (existingConfig == null) 
    db.Configurations.Add(configuration);
else 
    configuration = existingConfig;

db.SaveChanges();

Console.WriteLine($"Configuration owner = {configuration!.Owner?.GivenName} {configuration.Owner?.FamilyName}");
Console.ReadLine();

The errant line of code:

var existingConfig = db.Configurations.Include(c => c.Owner).FirstOrDefault(c => c.OwnerId == user.Id);

I'm using the preview release of MongoDb.EntityFrameworkCore.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <RootNamespace>mongo_example</RootNamespace>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.12" />
    <PackageReference Include="MongoDB.EntityFrameworkCore" Version="7.0.0-preview.1" />
  </ItemGroup>
</Project>

Maybe that is not the cause of the problem.

I'm expecting to be retrieve all Configuration entities along with their related User entity.

I've tried using both the fluent interface and property annotations to configure these entities, but the result is the same.

1

There are 1 best solutions below

0
Bill Richards On

This member of the Configuration model

    public void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Configuration>(e =>
        {
            e.HasOne<User>("Owner").WithMany("Configurations")
             .HasForeignKey(c => c.Id).IsRequired();
        });
    }

SHOULD read

    public void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Configuration>(e =>
        {
            e.HasOne<User>("Owner").WithMany("Configurations")
             .HasForeignKey(c => c.OwnerId).IsRequired();
        });
    }

In the original it was pointing to Configuration.Id as the foreign key, when it should have been pointing to Configuration.OwnerId.