1

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.

dinotom
  • 4,990
  • 16
  • 71
  • 139
  • Possible duplicate of https://stackoverflow.com/questions/5559043/entity-framework-code-first-two-foreign-keys-from-same-table – Dominik Szymański Nov 14 '17 at 00:24
  • @Dominik Szymanski... That post didn't come up in my search, thanks for the reference. It looks like the right solution. I am using .Net Core 2.0 and EF Core 2. The HasRequired in the entity builder seems to have been deprecated. Am I missing a library reference or is the another way to define that now. Resharper is not showing me a valid library for HasRequired. – dinotom Nov 14 '17 at 00:34
  • Please take a look at this: https://stackoverflow.com/questions/35098204/entity-framework-7-in-asp-net-mvc6-multiple-foreign-key-to-the-same-table It's not exactly the question you are asking, but has the solution you need and the solution for your potential problem. – Dominik Szymański Nov 14 '17 at 00:38
  • @Dominik Szymanski... That post is also helpful and IS very similar. I adjusted my code accordingly, see update in post, but am getting the same error. – dinotom Nov 14 '17 at 01:08
  • I'll take a look at your problem tomorrow, as I don't have MSBuild installed, or maybe someone will find the problem earlier ;) – Dominik Szymański Nov 14 '17 at 01:13
  • 1
    I got it working, needed to add the Icollection entities into the WithMany call i.e. builder.Entity(typeof(Message)) .HasOne(typeof(ApplicationUser), "MessageFromUser") .WithMany("SentMessages") .HasForeignKey("MessageFromUserId") .OnDelete(DeleteBehavior.Restrict); – dinotom Nov 14 '17 at 01:17

1 Answers1

1
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);
ceferrari
  • 1,597
  • 1
  • 20
  • 25
  • 1
    @ceferrari...We already had the solution, as noted above, upvoted you for the lambda form which I already was using. – dinotom Nov 14 '17 at 11:16