Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding a join entity instance doesn't populate collections on the participating entities #23659

Closed
andleer opened this issue Dec 11, 2020 · 4 comments
Labels
area-change-tracking closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported Servicing-approved type-bug
Milestone

Comments

@andleer
Copy link

andleer commented Dec 11, 2020

I don't know if this is a bug or am I missing something?

Two simple entities that are connected with a simple mapping table that contains a single payload item. Both (non-mapping) entities contain a collection of the opposing entity and a collection of the common mapping entity. If I add one of the non-mapping entities to the other's collection and attach the "base" entity to the context, the context mapping dbset is correctly populated but I am unable to default the mapping entity's payload in code or via fluent config.

I have tried populating the mapping entity along with the payload value and adding that to the context dbset and saving changes on the entity but the simple many to many collections on the non-mapping entities are not populated.

Seems like a catch 22.

  1. How do I set a payload value? Can it be set dynamically at runtime?
  2. If I need to build by graph via the mapping entity, why aren't the non-mapping collections updated?

Repo with tests:
https://github.com/andleer/BinaryOcean.EFCore5

EF Core version: 5.0.1
Database provider: Microsoft.EntityFrameworkCore.InMemory (5.0.1)
Target framework: .NET 5.0
Operating system: Win10
IDE: Microsoft Visual Studio Community 2019 Version 16.8.3

@roji
Copy link
Member

roji commented Dec 11, 2020

I've already investigated this to some extent, will soon paste a simplified repro on what is likely a bug.

@roji
Copy link
Member

roji commented Dec 12, 2020

The issue here seems to be that inserting a M2M join entity (PlayerGame) referencing new instances (Playere, Game) does not cause the navigation properties on the instances to be populated. In contrast, when inserting a Player with a Game in its Games list, the Game's Players list is populated.

@andleer as a workaround, you can reload the Player/Game from the database (see the use ChangerTracker.Clear below).

Minimal repro
var player = new Player { Name = "Andrew", };
var game = new Game { Name = "Rocket League", };
var playerGame = new PlayerGame
{
    Player = player,
    Game = game
};

ctx.PlayerGames.Add(playerGame);
await ctx.SaveChangesAsync();
Console.WriteLine(player.Games is null); // True

ctx.ChangeTracker.Clear();
player = await ctx.Players.Include(p => p.Games).SingleAsync();
Console.WriteLine(player.Games is null); // False

public class BlogContext : DbContext
{
    public DbSet<Player> Players { get; set; }
    public DbSet<Game> Games { get; set; }
    public DbSet<PlayerGame> PlayerGames { get; set; }

    static ILoggerFactory ContextLoggerFactory
        => LoggerFactory.Create(b => b.AddConsole().AddFilter("", LogLevel.Information));

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder
            .UseSqlServer(@"...")
            .EnableSensitiveDataLogging()
            .UseLoggerFactory(ContextLoggerFactory);

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Player>()
            .HasMany(e => e.Games)
            .WithMany(e => e.Players)
            .UsingEntity<PlayerGame>
            (
                e => e.HasOne(k => k.Game).WithMany(k => k.PlayerGames),
                e => e.HasOne(k => k.Player).WithMany(k => k.PlayerGames)
            );
    }
}

public class Player
{
    public int PlayerId { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Game> Games { get; set;  }
    public virtual ICollection<PlayerGame> PlayerGames { get; set;  }
}

public class Game
{
    public int GameId { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Player> Players { get; set; }
    public virtual ICollection<PlayerGame> PlayerGames { get; set;  }
}

public class PlayerGame
{
    public int PlayerId { get; set; }
    public int GameId { get; set; }
    public virtual Player Player { get; set; }
    public virtual Game Game { get; set; }
}

@andleer
Copy link
Author

andleer commented Dec 12, 2020

I agree with your assessment. Sorry I didn't spell that out before but it is pretty simple and I already have been using that as a workaround.

But are you confirming it is a bug or possible future functionality? We're a little into the world of esoteric at this point so it doesn't matter much either way. I am good and appreciate the feedback.

@roji
Copy link
Member

roji commented Dec 13, 2020

@andleer I think so, but let's let @AndriySvyryd confirm.

@roji roji changed the title Many to Many bug? Or Developer misunderstanding? Adding a join entity instance doesn't populate collections on the participating entities Dec 13, 2020
@ajcvickers ajcvickers self-assigned this Dec 15, 2020
@ajcvickers ajcvickers added this to the 5.0.3 milestone Dec 15, 2020
@ajcvickers ajcvickers added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Jan 4, 2021
ajcvickers added a commit that referenced this issue Jan 4, 2021
… with generated key values

This is a precursor to fixes for #23659, #23787. This test has no product changes, it just refactors the many-to-many tests so that they can be run with generated key values, as well as running with explicit keys values like they currently do. Generated keys result in more work being done in fixup by navigations, which is where both of these issues live.

Once this is merged I will send out separate PRs to fix the two bugs.
ajcvickers added a commit that referenced this issue Jan 4, 2021
Fixes #23659

If we encounter an unmapped entity during graph discovery of Attach, etc., then that entity is put aside for delayed fixup when it later becomes tracked. In this delayed fixup we were not populating skip navigations. The fix is to do this, just like happens in non-delayed fixup.
ajcvickers added a commit that referenced this issue Jan 5, 2021
… with generated key values (#23807)

This is a precursor to fixes for #23659, #23787. This test has no product changes, it just refactors the many-to-many tests so that they can be run with generated key values, as well as running with explicit keys values like they currently do. Generated keys result in more work being done in fixup by navigations, which is where both of these issues live.

Once this is merged I will send out separate PRs to fix the two bugs.
ajcvickers added a commit that referenced this issue Jan 5, 2021
Fixes #23659

If we encounter an unmapped entity during graph discovery of Attach, etc., then that entity is put aside for delayed fixup when it later becomes tracked. In this delayed fixup we were not populating skip navigations. The fix is to do this, just like happens in non-delayed fixup.
This was referenced Mar 15, 2021
@ajcvickers ajcvickers removed their assignment Sep 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-change-tracking closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported Servicing-approved type-bug
Projects
None yet
Development

No branches or pull requests

3 participants