dinotom
dinotom

Reputation: 5162

Code first migration modeling class with two AppUser references

I am trying to model a message class, for private messages for a user, using code first migrations.

public class Message
{
     public int MessageId { get; set; }

    [Required]
    public string MessageForUserId { get; set; }
    public virtual ApplicationUser MessageForUser { get; set; }

    [Required]
    public string MessageFromUserId { get; set; }

    public virtual ApplicationUser MessageFromUser { get; set; }

    [Required]
    public string MessageContent { get; set; }

    public bool MessageRead { get; set; }

    [Required]
    public DateTime MessageCreatedOn { get; set; }

    public DateTime? MessageReadOn { get; set; }
}

and in the ApplicationUser class I have added two collections

public class ApplicationUser : IdentityUser
{
    // other properties removed for brevity
    public ICollection<Message> UserMessages { get; set; }
    public ICollection<Message> SentMessages { get; set; }
}

When I do the migration I not only get the MessageFrom and MessageFor Id's, two additional Id's get added ApplicationUser_Id and ApplicationUser _Id1 to the Message table.

I know this because their are two foreign keys in message. The foreign key annotations are commented out right now as I was getting an error in migration.

This was the error when the ForeignKeys were live and I tried to migrate.

Unable to determine the relationship represented by navigation property 'ApplicationUser.UserMessages' of type 'ICollection'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.

I'd like to use fluent annotations to define this class in the OnModelCreating method but am not sure how to do this properly. I'm clearly not understanding why EF Code First is not determining the relationships.

The problem is that I am not sure how to define the message class foreign keys. Each message involves two users the sender and the receiver. I thought about splitting message into two classes, MessageSent and MessageReceived but that wouldn't help because each of those would have a sender and receiver as well.

Any assistance on how to define this properly using fluent annotations would be appreciated.

Update:

Following Dominick's recommendations and prior post references, I have tried the following which is not working.

This is the DbSet code

 public DbSet<Message> Messages { get; set; }
 public DbSet<ApplicationUser> AppUsers { get; set; }

And in OnModelCreating

 builder.Entity(typeof(Message))
            .HasOne(typeof(ApplicationUser), "MessageFromUser")
            .WithMany()
            .HasForeignKey("MessageFromUserId")
            .OnDelete(DeleteBehavior.Restrict); // no ON DELETE

 builder.Entity(typeof(Message))
            .HasOne(typeof(ApplicationUser), "MessageForUser")
            .WithMany()
            .HasForeignKey("MessageForUserId")
            .OnDelete(DeleteBehavior.Cascade); // set ON DELETE CASCADE

I am getting the same error as noted above, even though the builder options make sense. The entity has one type of ApplicationUser, MessagesFromUser, there can be many and the foreignkey id is correct. Same is true for the other property.

Upvotes: 1

Views: 56

Answers (1)

ceferrari
ceferrari

Reputation: 1677

builder.Entity<Message>()
    .HasOne(x => x.MessageForUser)
    .WithMany(x => x.UserMessages)
    .HasForeignKey(x => x.MessageForUserId)
    .OnDelete(DeleteBehavior.Cascade);

builder.Entity<Message>()
    .HasOne(x => x.MessageFromUser)
    .WithMany(x => x.SentMessages)
    .HasForeignKey(x => x.MessageFromUserId)
    .OnDelete(DeleteBehavior.Cascade);

Upvotes: 1

Related Questions