Supponiamo di avere una classe che assomiglia al seguente:
public class Entity
{
public IList<string> SomeListOfValues { get; set; }
// Other code
}
Ora, supponiamo di voler persistere usando EF Code First e che stiamo usando un RDMBS come SQL Server.
Un possibile approccio è ovviamente quello di creare una wrapper di classe Wraper
che avvolge la stringa:
public class Wraper
{
public int Id { get; set; }
public string Value { get; set; }
}
E per refactoring della classe in modo che ora dipende da un elenco di oggetti Wraper
. In quel caso EF genererebbe una tabella per Entity
, una tabella per Wraper
e stabilirà una relazione "uno a molti": per ogni entità c'è un gruppo di wrapers.
Anche se questo funziona, non mi piace l'approccio perché stiamo cambiando un modello molto semplice a causa di problemi di persistenza. In effetti, pensando solo al modello di dominio e al codice, senza la persistenza, la classe Wraper
è del tutto priva di significato.
C'è un altro modo per mantenere un'entità con un elenco di stringhe su un RDBMS usando EF Core Code Prima di creare una classe wrapper? Naturalmente, alla fine, bisogna fare la stessa cosa: bisogna creare un altro tavolo per tenere le corde e una relazione "da uno a molti" deve essere in atto. Voglio solo farlo con EF Core senza dover codificare la classe wraper nel modello di dominio.
Ciò può essere ottenuto in un modo molto più semplice a partire da Entity Framework Core 2.1 . EF ora supporta Value Conversions per affrontare in modo specifico scenari come questo in cui una proprietà deve essere mappata su un tipo diverso per l'archiviazione.
Per DbContext
persistente una raccolta di stringhe, è possibile configurare DbContext
nel modo seguente:
protected override void OnModelCreating(ModelBuilder builder)
{
var splitStringConverter = new ValueConverter<IEnumerable<string>, string>(v => string.Join(";", v), v => v.Split(new[] { ';' }));
builder.Entity<Entity>().Property(nameof(Entity.SomeListOfValues)).HasConversion(splitStringConverter);
}
Nota che questa soluzione non sporca la tua business class con problemi di DB.
Inutile dire che questa soluzione, si dovrebbe assicurarsi che le stringhe non possano contenere il delimitatore. Ma ovviamente, qualsiasi logica personalizzata potrebbe essere utilizzata per effettuare la conversione (ad es. Conversione da / a JSON).
Un altro fatto interessante è che i valori null non vengono passati alla routine di conversione ma piuttosto gestiti dal framework stesso. Quindi non è necessario preoccuparsi dei controlli null all'interno della routine di conversione. Tuttavia, l'intera proprietà diventa null
se il database contiene un valore NULL
.