简体   繁体   中英

Entity Framework Core with Multiple Foreign Key On Same Column

I have 3 tables with relationship to the same TransactionLog.DocumentId column. I differentiate the Foreign Key with DocumentTypeId:

1 - Invoice, 2 - DebitNote, 3 - CreditNote

在此处输入图片说明

I scaffold the entities:

public partial class TransactionLog
{
    public int TransactionLogId { get; set; }
    public int? DocumentId { get; set; }
    public int? DocumentTypeId { get; set; }
    public decimal? Amount { get; set; }

    public CreditNote CreditNote { get; set; }
    public Invoice Invoice { get; set; }
    public DebitNote DebitNote { get; set; }
}

public partial class Invoice
{
    public Invoice()
    {
        TransactionLog = new HashSet<TransactionLog>();
    }

    public int InvoiceId { get; set; }
    public string InvoiceNumber { get; set; }
    public decimal Amount { get; set; }

    public ICollection<TransactionLog> TransactionLog { get; set; }
}

public partial class DebitNote
{
    public DebitNote()
    {
        TransactionLog = new HashSet<TransactionLog>();
    }

    public int DebitNoteId { get; set; }
    public string DebitNoteNumber { get; set; }
    public decimal Amount { get; set; }

    public ICollection<TransactionLog> TransactionLog { get; set; }
}

public partial class CreditNote
{
    public CreditNote()
    {
        TransactionLog = new HashSet<TransactionLog>();
    }

    public int CreditNoteId { get; set; }
    public string CreditNoteNumber { get; set; }
    public decimal Amount { get; set; }

    public ICollection<TransactionLog> TransactionLog { get; set; }
}

I want to insert 1 record to each of the table Invoice, DebitNote and CreditNote, and 3 records for each transaction to TransactionLog.

And this is my code:

在此处输入图片说明

protected override void OnModelCreating(ModelBuilder modelBuilder)
    {

        modelBuilder.Entity<CreditNote>(entity =>
        {
            entity.Property(e => e.Amount).HasColumnType("decimal(18, 4)");

            entity.Property(e => e.CreditNoteNumber)
                .HasMaxLength(50)
                .IsUnicode(false);
        });

        modelBuilder.Entity<DebitNote>(entity =>
        {
            entity.Property(e => e.Amount).HasColumnType("decimal(18, 4)");

            entity.Property(e => e.DebitNoteNumber)
                .HasMaxLength(50)
                .IsUnicode(false);
        });

        modelBuilder.Entity<Invoice>(entity =>
        {
            entity.Property(e => e.Amount).HasColumnType("decimal(18, 4)");

            entity.Property(e => e.InvoiceNumber)
                .HasMaxLength(50)
                .IsUnicode(false);
        });

        modelBuilder.Entity<TransactionLog>(entity =>
        {
            entity.Property(e => e.Amount).HasColumnType("decimal(18, 4)");

            entity.HasOne(d => d.CreditNote)
                .WithMany(p => p.TransactionLog)
                .HasForeignKey(d => d.DocumentId)
                .HasConstraintName("FK_TransactionLog_CreditNote");

            entity.HasOne(d => d.DebitNote)
                .WithMany(p => p.TransactionLog)
                .HasForeignKey(d => d.DocumentId)
                .HasConstraintName("FK_TransactionLog_DebitNote");

            entity.HasOne(d => d.Invoice)
                .WithMany(p => p.TransactionLog)
                .HasForeignKey(d => d.DocumentId)
                .HasConstraintName("FK_TransactionLog_Invoice");
        });
    }

However, the DocumentId doesn't save the correct InvoiceId, CreditNoteId, DebitNoteId. I check with SQL Profiler, it will always get the first scope_identity() of the 3 inserts, which in my case is CreditNoteid.

在此处输入图片说明

Any idea how to get the correct Id from Invoice, CreditNote and DebitNote ? Or shouldn't I use relationship in this case. If not, what is the best practice of logging the transaction into the log?

Add the following configurations in your DbContext and then add a migration and update the database accordingly.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<Invoice>().HasMany(i => i.TransactionLog).WithOne(tl => tl.Invoice).HasForeignKey(tl => tl.DocumentId);
    modelBuilder.Entity<DebitNote>().HasMany(dn => dn.TransactionLog).WithOne(tl => tl.DebitNote).HasForeignKey(tl => tl.DocumentId);
    modelBuilder.Entity<CreditNote>().HasMany(cn => cn.TransactionLog).WithOne(tl => tl.CreditNote).HasForeignKey(tl => tl.DocumentId);
}

I think maybe the Foreign Key's direction is wrong.

As your table definition, the TransactionLog.DocumentId 's value must be exist in the three tables ( Invoice CreditNote DebitNote ) at the same time. So, if only insert two of them, there will maybe have a Exception.

在此处输入图片说明

I think you really want table definition is like this. I delete TransactionLog.DocumentId column and add FKs from the PK of the three tables to TransactionLog.TransactionLogId .

在此处输入图片说明

the entities:

public partial class TransactionLog
{
    public int TransactionLogId { get; set; }
    public Nullable<int> DocumentTypeId { get; set; }
    public Nullable<decimal> Amount { get; set; }

    public virtual CreditNote CreditNote { get; set; }
    public virtual DebitNote DebitNote { get; set; }
    public virtual Invoice Invoice { get; set; }
}

public partial class Invoice
{
    public int InvoiceId { get; set; }
    public string InvoiceNumber { get; set; }
    public decimal Amount { get; set; }

    public virtual TransactionLog TransactionLog { get; set; }
}

public partial class CreditNote
{
    public int CreditNoteId { get; set; }
    public string CreditNoteNumber { get; set; }
    public decimal Amount { get; set; }

    public virtual TransactionLog TransactionLog { get; set; }
}

public partial class DebitNote
{
    public int DebitNoteId { get; set; }
    public string DebitNoteNumber { get; set; }
    public decimal Amount { get; set; }

    public virtual TransactionLog TransactionLog { get; set; }
}

code:

Invoice invoice = new Invoice() { InvoiceNumber = "Inv0100", Amount = 66m };
TransactionLog invoiceLog = new TransactionLog() { Amount = invoice.Amount, DocumentTypeId = 1 };
invoice.TransactionLog = invoiceLog;
_context.Invoices.Add(invoice);

CreditNote creditNote = new CreditNote() { CreditNoteNumber = "DN003", Amount = 99.99m };
TransactionLog creditNoteLog = new TransactionLog() { Amount = creditNote.Amount, DocumentTypeId = 2 };
creditNote.TransactionLog = creditNoteLog;
_context.CreditNotes.Add(creditNote);

DebitNote debitNote = new DebitNote() { DebitNoteNumber = "CN009", Amount = 77.77m };
TransactionLog debitNoteLog = new TransactionLog() { Amount = debitNote.Amount, DocumentTypeId = 3 };
debitNote.TransactionLog = debitNoteLog;
_context.DebitNotes.Add(debitNote);

I guess you have a wrong relationship there. like one transaction can have multiple invoices but an invoice will have only one transaction record. I might be wrong because sometimes it feels like one-to-one but anyways I gave it a try and here is what you want.

the entities:

public class TestMVCEntities : DbContext
{

    public TestMVCEntities()
        : base("name=TestMVCEntities")
    {
    }

    public DbSet<Invoice> Invoices { get; set; }
    public DbSet<DebitNote> DebitNotes { get; set; }
    public DbSet<CreditNote> CreditNotes { get; set; }
    public DbSet<TransactionLog> TransactionLogs { get; set; }


    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<TransactionLog>()
            .HasRequired(p => p.Invoice)
            .WithMany(p => p.InvoiceLog)
            .HasForeignKey(p => p.DocumentId);

        modelBuilder.Entity<TransactionLog>()
            .HasRequired(p => p.DebitNote)
            .WithMany(p => p.DebitLog)
            .HasForeignKey(p => p.DocumentId);

        modelBuilder.Entity<TransactionLog>()
            .HasRequired(p => p.CreditNote)
            .WithMany(p => p.CreditLog)
            .HasForeignKey(p => p.DocumentId);
    }
}

public partial class TransactionLog
{
    public int TransactionLogId { get; set; }
    public int? DocumentId { get; set; }
    public int? DocumentTypeId { get; set; }
    public decimal? Amount { get; set; }

    public CreditNote CreditNote { get; set; }
    public Invoice Invoice { get; set; }
    public DebitNote DebitNote { get; set; }
}

public partial class Invoice
{
    public int InvoiceId { get; set; }
    public string InvoiceNumber { get; set; }
    public decimal Amount { get; set; }

    public ICollection<TransactionLog> InvoiceLog { get; set; }
}

public partial class DebitNote
{
    public int DebitNoteId { get; set; }
    public string DebitNoteNumber { get; set; }
    public decimal Amount { get; set; }

    public ICollection<TransactionLog> DebitLog { get; set; }
}

public partial class CreditNote
{
    public int CreditNoteId { get; set; }
    public string CreditNoteNumber { get; set; }
    public decimal Amount { get; set; }

    public ICollection<TransactionLog> CreditLog { get; set; }
}  

and to insert data:

var invoice = new Invoice()
    {
        InvoiceNumber = "Inv099",
        Amount = 66m,
        InvoiceLog = new Collection<TransactionLog>()
        {
            new TransactionLog(){DocumentTypeId = 1, Amount = 66m}
        }
    };

    var creditNote = new CreditNote()
    {
        CreditNoteNumber = "DN002",
        Amount = 99.99m,
        CreditLog = new Collection<TransactionLog>()
        {
            new TransactionLog(){DocumentTypeId = 3, Amount = 99.99m}
        }
    };

    var debitNote = new DebitNote()
    {
        DebitNoteNumber = "CN008",
        Amount = 77.77m,
        DebitLog = new Collection<TransactionLog>()
        {
            new TransactionLog(){DocumentTypeId = 2, Amount = 77.77m}
        }
    };

    using (var context = new TestMVCEntities())
    {
        context.Invoices.Add(invoice);
        context.CreditNotes.Add(creditNote);
        context.DebitNotes.Add(debitNote);
        context.SaveChanges();
    }  

and the table will look like this:

在此处输入图片说明

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