简体   繁体   中英

Multiple foreign keys on the same table. How to redesign my model?

I wanted to create a simple MoneyTransaction model with EF Core as you can see below, and I ran into the following error:

An exception of type 'System.InvalidOperationException' occurred in Microsoft.EntityFrameworkCore.dll but was not handled in user code: 'Cannot create a relationship between 'Member.MoneyTransactions' and 'MoneyTransaction.PaidBy' because a relationship already exists between 'Member.MoneyTransactions' and 'MoneyTransaction.ChargedBy'. Navigation properties can only participate in a single relationship. If you want to override an existing relationship call 'Ignore' on the navigation 'MoneyTransaction.PaidBy' first in 'OnModelCreating'.'

Here my code I have written so far:

public class Member
{
    // ...
    public string MoneyTransactionsId { get; set; }
    public ICollection<MoneyTransaction> MoneyTransactions { get; set; } = new List<MoneyTransaction>();
    // ...
}

public class MoneyTransaction
{
    // ...
    public string PaidById { get; set; }
    public Member PaidBy { get; set; }
    public string ChargedById { get; set; }
    public Member ChargedBy { get; set; }
    // ...
}

And the problem occurs in the OnModelCreating:

protected override void OnModelCreating(ModelBuilder builder)
{
    // ...
    builder.Entity<Member>()
        .HasMany(m => m.MoneyTransactions)
        .WithOne(t => t.PaidBy)
        .HasForeignKey(t => t.PaidById)
        .OnDelete(DeleteBehavior.NoAction)
        .HasPrincipalKey(m => m.Id);
    builder.Entity<Member>()
        .HasMany(m => m.MoneyTransactions)
        .WithOne(t => t.ChargedBy)
        .HasForeignKey(t => t.ChargedById)
        .HasPrincipalKey(m => m.Id);
    // ...
}

I'm not sure how I can design my model to get it to work via Fluent API only (don't want to have DataAnnotations in my model classes). It is probably a simple solution, but somehow I could not find anything useful to refactor my model to get it to work.

Since a Member can both charge or pay in a transaction, it should have two list of MoneyTransaction - one for which they charged and one for which they paid -

public class Member
{
    // ...
    public string MoneyTransactionsId { get; set; }
    public ICollection<MoneyTransaction> ChargedTransactions { get; set; } = new List<MoneyTransaction>();
    public ICollection<MoneyTransaction> PaidTransactions { get; set; } = new List<MoneyTransaction>();
    // ...
}

Then you can configure them as -

builder.Entity<Member>()
    .HasMany(m => m.PaidTransactions)
    .WithOne(t => t.PaidBy)
    .HasForeignKey(t => t.PaidById)
    .OnDelete(DeleteBehavior.NoAction)
    .HasPrincipalKey(m => m.Id);
    
builder.Entity<Member>()
    .HasMany(m => m.ChargedTransactions)
    .WithOne(t => t.ChargedBy)
    .HasForeignKey(t => t.ChargedById)
    .HasPrincipalKey(m => m.Id);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM