Sto avendo qualche problema ad entrare nella relazione EF Core.
Non sapevo come cercarlo correttamente, quindi non ho trovato quello che mi serve, ma sono arrivato da qualche parte.
Ho queste due classi:
Spese:
public class Expense : Entity
{
public string Title { get; set; }
public string Description { get; set; }
public decimal Amount { get; set; }
public List<ExpenseType> Types { get; set; }
public ValidationResult ValidationResult { get; private set; }
public bool IsValid
{
get
{
var fiscal = new ExpenseIsValidValidation();
ValidationResult = fiscal.Valid(this);
return ValidationResult.IsValid;
}
}}
ExepenseType:
public class ExpenseType : Entity
{
#region properties
public string Name { get; private set; }
public string Description { get; private set; }
public ValidationResult ValidationResult { get; private set; }
public bool IsValid
{
get
{
var fiscal = new ExpenseTypeIsValidValidation();
ValidationResult = fiscal.Valid(this);
return ValidationResult.IsValid;
}
}}
Durante ToListAsync in ExpenseType, EF aggiunge la colonna "expenseId" alla query, ma questa colonna non esiste.
Il mio database ha tre tabelle, una per ogni classe e una per la relazione. (Expense, ExpenseType e Expense_ExpenseType)
Cercando la soluzione qui su StackOverflow ho scoperto che dovrei avere una classe per il terzo tavolo. Ecco qui:
public class Expense_ExpenseType
{
public int ExpenseId { get; set; }
public Expense Expense { get; set; }
public int ExpenseTypeId { get; set; }
public ExpenseType ExpenseType { get; set; }
}
La mia idea è che posso avere un ExpenseType senza avere una spesa, e posso avere una spesa senza ExpeseType o con quante ne voglio.
Quindi ExpenseType non ha alcuna spesa.
Non sono sicuro di cosa dovrei fare ora. Dovrei mappare usando optionsBuilder? Come? Devo riscrivere il database?
Se vuoi creare una relazione molti-a-molti, hai diverse opzioni su come farlo:
Crea un corso aggiuntivo come hai descritto. In questo caso EF creerà la tabella e potrai ottenere l'accesso per ottenere valori solo da questa tabella.
public class Expense_ExpenseType
{
public int ExpenseId { get; set; }
public Expense Expense { get; set; }
public int ExpenseTypeId { get; set; }
public ExpenseType ExpenseType { get; set; }
}
Potresti non creare classi e solo descrivere nella relazione di contesto. Dove descriveresti tutto e EF creerà da solo questo tavolo. Ma dall'app non vedrai questo tavolo. Devi usare questa variante se non vuoi estendere la tabella con campi aggiuntivi.
modelBuilder
.Entity<Student>()
.HasMany<Course>(s => s.Courses)
.WithMany(c => c.Students)
.Map(cs =>
{
cs.MapLeftKey("StudentRefId");
cs.MapRightKey("CourseRefId");
cs.ToTable("StudentCourse");
});
Per questa relazione puoi leggere di più qui
Ma nel tuo caso non hai bisogno di usare Many-to-Many. Ecco perché se non vuoi aggiungere ExpanseTypeId
o ExpenseId
nel tuo modello puoi descriverlo in questo modo:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Expense>()
.HasMany<ExpenseType>(o => o.Types) //It is your list of expense types.
.WithOne() //Here you can add model for expense. To have an option go back from expense type to expense
.HasForeignKey("ForeignKey");//This key EF will create for you in DB but not in you app model
}
Cosa vuoi usare devi decidere. Se hai un'idea che la spesa ha un sacco di expensetypes e ogni tipo di spesa ha un sacco di spese. Devi usare Many-To-Many come ho descritto.
Penso che la tua domanda principale sia "La mia idea è che posso avere un ExpenseType senza avere una spesa, e posso avere una spesa senza ExpeseType o con tutti quelli che voglio."
quindi puoi farlo creando una chiave straniera nullable ExpenseTypeId nella classe Expanse e HashSet of Expanse nella classe ExpeseType.
Come questo:
public class ExpenseType : Entity
{
public ICollection<Expanse> Expanses {get; set;} = new HashSet<Expanse>()
}
public class Expense : Entity
{
public int? ExpanseTypeId {get; set;}
public ExpanseType ExpanseType {get; set;}
}