Tutto, è possibile utilizzare lo stesso FK per due tavoli. Probabilmente non è una buona pratica, ma ho due classi diverse che possono essere prenotate entrambe:
public class Course {
public Course() {
BookingRefs = new HashSet<BookingRef>();
}
public long Id { get; set; }
public string Title { get; set; }
// other props ...
[InverseProperty(nameof(BookingRef.Course))]
public virtual ICollection<BookingRef> BookingRefs { get; set; }
}
public class GiftCard {
public GiftCard() {
BookingRefs = new HashSet<BookingRef>();
}
public long Id { get; set; }
public string Prop1 { get; set; }
public int Prop2 { get; set; }
// other props ...
[InverseProperty(nameof(BookingRef.Course))]
public virtual ICollection<BookingRef> BookingRefs { get; set; }
}
// this is the bookin reference for a Course or an GiftCard
public class BookingRef {
public BookingRef() {
}
public long Id { get; set; }
// other props ...
/// <summary>The item (usually the course but theoretically anything with a long id)</summary>
public long? ItemId { get; set; }
// maybe a generic Object?
[ForeignKey(nameof(ItemId))]
public Object GiftCard { get; set; }
// maybe 2 items possibly null?
[ForeignKey(nameof(ItemId))]
public Course Course { get; set; }
// maybe 2 items possibly null?
[ForeignKey(nameof(ItemId))]
public GiftCard GiftCard { get; set; }
}
Pensaci dal punto di vista dei dati relazionali. In che modo il database dovrebbe sapere a quale tabella è indicato un "Item ID"? Come lo indicizzerebbe?
Questo sarebbe un caso per l'utilizzo di un FK nullo per ogni tabella correlata nella prenotazione. Questi FK non hanno bisogno di risiedere nell'entità, solo le proprietà di navigazione. Puoi sfruttare .Map(x => x.MapKey)
in EF6 o .HasForeignKey("")
in EF Core per sfruttare una proprietà shadow.
Ciò non impone se si desidera che una prenotazione sia associata a un corso o a una carta regalo, ma non entrambi. Ciò dovrebbe essere previsto a livello di applicazione e suggerirei di utilizzare un'attività di manutenzione pianificata per valutare i dati relativi a violazioni a tale regola. (Cerca le prenotazioni che contengono sia l'ID del corso che l'ID della carta regalo, ad esempio)
In alternativa, è possibile mantenere i join "liberi" e valutati dall'applicazione in base a un discriminatore simile a un modello di ereditarietà. (ItemId + ItemType) Tuttavia, è necessario risolvere il carico delle relazioni separatamente nell'applicazione in base a ItemType e perdere i controlli di integrità FK, indicizzazione e integrità dei dati nel database. Ciò potrebbe comportare costi significativi di prestazioni e manutenzione per risparmiare l'aggiunta di un paio di FK.