Piotrek
Piotrek

Reputation: 11221

Problem with seeding data in many-to-many relationship. Cannot make migration

I'm trying to seed data in many-to-many relation in my database, but I cannot make a migration. I'm using Entity Framework Core 5.0.6.

Here are my models:

The general idea is: one Tag can belong to many Topics. One Topic can have many Tags.

Tag.cs:

public class Tag
{
    public int Id { get; set; }

    // [...]    

    public ICollection<Topic> Topics { get; set; }
    public List<TopicTag> TopicTags { get; set; }
}

Topic.cs

public class Topic
{
    public int Id { get; set; }

    // [...]

    public ICollection<Tag> Tags { get; set; }
    public List<TopicTag> TopicTags { get; set; }
}

And TopicTag.cs

public class TopicTag
{
    public int TopicId { get; set; }
    public Topic Topic { get; set; }
    
    public int TagId { get; set; }
    public Tag Tag { get; set; }
}

Here is what I have in OnModelCreating in my ApplicationDbContext:

// [...]
// Configuring relation
modelBuilder.Entity<Topic>()
    .HasMany(topic => topic.Tags)
    .WithMany(x => x.Topics)
    .UsingEntity<TopicTag>(
        j => j
            .HasOne(tt => tt.Tag)
            .WithMany(t => t.TopicTags)
            .HasForeignKey(t => t.TagId),
        j => j
            .HasOne(tt => tt.Topic)
            .WithMany(t => t.TopicTags)
            .HasForeignKey(t => t.TopicId),
        j => { j.HasKey(t => new {t.TopicId, t.TagId}); }
    );

modelBuilder.Entity<Tag>()
    .HasMany(tag => tag.Topics)
    .WithMany(x => x.Tags)
    .UsingEntity<TopicTag>(
        j => j
            .HasOne(tt => tt.Topic)
            .WithMany(t => t.TopicTags)
            .HasForeignKey(t => t.TopicId),
        j => j
            .HasOne(tt => tt.Tag)
            .WithMany(t => t.TopicTags)
            .HasForeignKey(t => t.TagId),
        j => { j.HasKey(t => new {t.TopicId, t.TagId}); }
    );
// [...]

// Seeding data

for (int t = -1; t >= -4; t--)
{
    builder.Entity<Tag>().HasData(new Tag()
    {
        Id = t,
        Name = "tag" + t
    });
}

for (int y = -1; y >= -10; y--)
{
    builder.Entity<Topic>().HasData(new Topic()
    {
        Id = y,
        // [...]
    });
}

// Finally joining them together
for (int y = -1; y >= -10; y--)
{
    builder.Entity<TopicTag>().HasData(new TopicTag()
    {
        TopicId = y,
        TagId = -1 * ((y % 4) + 1)
    });
}

As a result, when I try to create new migration, I receive this error:

The value of 'TopicTag.TagId' is unknown when attempting to save changes. This is because the property is also part of a foreign key for which the principal entity in the relationship is not known.

To be honest, I don't understand the meaning of an error message. TopicTag.TagId is known, because I'm specifying it while creating new TopicTag in for loop. Moreover, all ids I'm referencing there are created before.

Upvotes: 1

Views: 119

Answers (1)

RBarryYoung
RBarryYoung

Reputation: 56745

I fear that you've fallen afoul of a nasty "feature" of C#'s modulo operator.

Let's consider your last loop:

/ Finally joining them together
for (int y = -1; y >= -10; y--)
{
    builder.Entity<TopicTag>().HasData(new TopicTag()
    {
        TopicId = y,
        TagId = -1 * ((y % 4) + 1)
    });
}

So what happens on the first iteration through the loop? You may think that (-1 % 4) returns something reasonable like 3, but in fact it actually returns -1! So the whole expression resolves to -1 * (-1 + 1) == 0 and not -4 which is probably what you wanted. And since you don't have any tag IDs that are zero, that's where the TagId is not known message is coming from.

To address this you can try some of the solutions here: Mod of negative number is melting my brain

Upvotes: 1

Related Questions