Ho due classi, una per User
e una per Warn
che un utente può ricevere, e vorrei mapparle, ma ho un problema nel farlo.
using System;
using System.Collections.Generic;
using System.Linq;
namespace web
{
public class User
{
public User()
{
}
public ICollection<MuteWarn> Mutes { get; set; }
public ICollection<Warn> Warns { get; set; }
public ICollection<Ban> Bans { get; set; }
public ICollection<Kick> Kicks { get; set; }
public int Id { get; set; }
public ulong DiscordId { get; set; }
public bool AntiBan { get; set; }
public ICollection<string> Permissions { get; set; }
public Level Level { get; set; }
public Mute CurrentMute { get; set; }
public string Name { get; set; }
public int Discrim { get; set; }
public string AvatarUrl { get; set; }
public Guild Guild { get; set; }
public bool HasPermission(string perm)
{
var res = Permissions.Where(x => x == perm);
if(res != null) return true;
return false;
}
}
}
Questa è la classe User
, ed ecco la classe Warn
:
using System;
namespace web
{
public class Warn
{
public Warn()
{
Moderator = DataHelper.GetDefaultModerator();
}
public int Id { get; set; }
public string Reason { get; set; }
public DateTime Timestamp { get; set; }
public User Moderator { get; set; }
public User User { get; set; }
public Guild Guild { get; set; }
}
}
Come puoi vedere ci sono due oggetti di tipo User
in questa classe, e mi piacerebbe accedervi dalla classe User in questo modo:
foreach(var w in User.Warns)
{
Console.WriteLine(w.Reason);
Console.WriteLine(w.Moderator.Name);
}
e così via.
Il moderatore e l'utente sono due utenti separati (anche se possono essere la stessa persona).
Il moderatore è la persona che emette questo avviso e l'utente è l'utente che riceve l'avvertimento.
Ogni utente può avere un numero illimitato di avvisi.
Per qualche motivo questo non si costruisce perché non riesce a trovare la relazione tra Moderatore e Utente.
Per favore, aiuto, grazie.
EF Core ha convenzioni per capire parti di metadati basate sulla struttura delle classi di dominio. Generalmente la proprietà di navigazione rappresenta l'esistenza di una relazione tra tipo dichiarante e tipo di destinazione. E se esiste una navigazione nel tipo di destinazione di tipo dichiarante, vengono considerate coppie di navigazione che definiscono la relazione. Sebbene ci sia una limitazione in termini di ricerca di coppie di navigazioni che costituiscono una relazione. Se c'è ambiguità, EF Core non creerà relazioni. Nel tuo caso User
classe ha una navigazione Warns
che ha tipo di destinazione Warn
ma classe Warn
ha 2 navigazioni di tipo User
- Moderator
e User
. Ora EF non riesce a capire quali navigazioni facciano parte della singola relazione. Quindi ciò richiede la configurazione dell'utente per definire la relazione, quindi costruire correttamente il modello.
Supponendo che User.Warns
& Warn.User
parte di 1 relazione poiché Warns contiene tutti gli avvisi che l'utente riceve, quindi Warn.User
dovrebbe puntare a User
. E Warn.Moderator
è una relazione separata senza navigazione inversa. Ci sono 2 modi per configurarlo.
Annotazioni dei dati
Puoi usare InverseProperty
attributo InverseProperty
sulla tua navigazione per dire a EF Core qual è la navigazione inversa per questa navigazione. Nel tuo caso, uno di questi risolverà il problema.
[InverseProperty("User")]
public ICollection<Warn> Warns { get; set; }
o
[InverseProperty("Warns")]
public User User { get; set; }
Ciò risolverebbe l'ambiguità e aiuterebbe EF a scoprire le coppie in modo che la convenzione crei relazioni.
API fluente
È possibile utilizzare API fluenti per configurare esplicitamente la relazione. Devi inserire questo codice nel tuo metodo DbContext.OnModelCreating
.
modelBuilder.Entity<User>().HasMany(e => e.Warns).WithOne(e => e.User);
o
modelBuilder.Entity<Warn>().HasOne(e => e.Moderator).WithMany();
Ancora una volta la definizione di quanto sopra chiarisce l'ambiguità e la compilazione del modello correttamente.
Per ulteriori dettagli su come configurare le relazioni, è possibile leggere nella documentazione