Sto seguendo questa domanda: Primo codice EF - Relazione opzionale 1-a-1
E ho le mie relazioni stabilite come segue:
public class Review {
[Key]
public int ReviewId { get; set; }
public virtual Payment Payment { get; set; }
}
public class Payment {
[Key]
public int PaymentId { get; set; }
[ForeignKey("Review")]
public int? ReviewId { get; set; }
public virtual Review Review { get; set; }
}
public class ReviewConfiguration : EntityTypeConfiguration<Review>
{
public ReviewConfiguration()
{
// One-to-One Optional
HasOptional<Payment>(s => s.Payment).WithOptionalDependent(s => s.Review).Map(s => s.MapKey("PaymentId"));
}
}
E ottengo UNO dei tasti valido, ma l'altro non è mai mappato come FK facoltativo:
Che cosa sto facendo di sbagliato?
Ho visto alcune strane soluzioni hacky che implicano la creazione di elenchi vuoti ecc. Non è quello che sto cercando. Sto cercando un approccio corretto qui - deve esistere ... giusto?
Aggiornare
Sto usando quanto sopra ora - quando ho il pagamento a portata di mano e ho bisogno di accedere o eliminare la recensione, devo fare un'altra ricerca su [pseudo-FK] ReviewId, che fa schifo.
In ogni associazione uno-a-uno, EF usa solo una chiave esterna. Quando è richiesta l'associazione, la chiave esterna sarà anche la chiave primaria dell'entità dipendente, come spiegato qui .
Quando l'associazione è facoltativa, entrambe le entità dovrebbero essere in grado di esistere indipendentemente l'una dall'altra. Quindi le loro chiavi primarie non possono essere chiavi esterne, perché i PK non possono essere opzionali. Qui è richiesto un campo FK Null aggiuntivo per stabilire l'associazione facoltativa.
Nel tuo caso, tecnicamente non importa quale entità abbia il campo FK ( logicamente , potrebbe). Ho usato questo modello:
public class Review
{
[Key]
public int ReviewId { get; set; }
public virtual Payment Payment { get; set; }
}
public class Payment
{
[Key]
public int PaymentId { get; set; }
public Review Review { get; set; }
}
Con questa mappatura:
public class ReviewConfiguration : EntityTypeConfiguration<Review>
{
public ReviewConfiguration()
{
// One-to-One Optional
HasOptional(s => s.Payment)
.WithOptionalDependent(s => s.Review)
.Map(s => s.MapKey("PaymentId"));
}
}
(Quindi, a parte Payment.ReviewId
, questo è identico al mapping del modello + nella tua domanda).
Ora posso fare cose come ...
db.Set<Review>().Add(new Review { Payment = new Payment() });
db.Set<Payment>().Add(new Payment { Review = new Review() });
db.SaveChanges();
... dove db
naturalmente, è un contesto. Il contenuto di entrambe le tabelle ora è:
PaymentId
-----------
1
2
ReviewId PaymentId
----------- -----------
1 1
2 2
E posso interrogare i dati in modo bidirezionale in questo modo:
var data = db.Set<Review>().Include(r => r.Payment).ToList();
o
var data = db.Set<Payment>().Include(r => r.Review).ToList();
Ma invece di ReviewConfiguration
, posso anche usare ...
public class PaymentConfiguration : EntityTypeConfiguration<Payment>
{
public PaymentConfiguration()
{
// One-to-One Optional
HasOptional(s => s.Review)
.WithOptionalDependent(s => s.Payment)
.Map(s => s.MapKey("ReviewId"));
}
}
Ora ci sarà un campo FK ReviewId
nella tabella di Payment
, e il resto del codice funziona senza modifiche.
Devi avere errori di battitura nei tuoi modelli (2 campi ReviewId in pagamento?). Inoltre, se stai percorrendo la via fluente, non inserire attributi di relazione per confondere le cose. IAC, prova qualcosa del genere:
public class Review {
public int ReviewId { get; set; }
public int? PaymentId { get; set; }
public virtual Payment Payment { get; set; }
}
public class Payment {
public int PaymentId { get; set; }
public int? ReviewId { get; set; }
public virtual Review Review { get; set; }
}
public class ReviewConfiguration : EntityTypeConfiguration<Review>
{
public ReviewConfiguration()
{
HasOptional(r => r.Payment)
.WithMany()
.HasForeignKey(r => r.PaymentId);
}
}
public class PaymentConfiguration : EntityTypeConfiguration<Payment>
{
public PaymentConfiguration()
{
HasOptional(p => p.Review)
.WithMany()
.HasForeignKey(p => p.ReviewId);
}
}