Proprietà dell'entità
Ogni tipo di entità nel modello ha un set di proprietà, che EF Core leggerà e scriverà dal database. Se si usa un database relazionale, le proprietà delle entità vengono mappate alle colonne della tabella.
Proprietà incluse ed escluse
Per convenzione e, tutte le proprietà pubbliche con un getter e un setter verranno incluse nel modello.
Le proprietà specifiche possono essere escluse nel modo seguente:
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
[NotMapped]
public DateTime LoadedFromDatabase { get; set; }
}
Nomi delle colonne
Per convenzione, quando si usa un database relazionale, le proprietà dell'entità vengono mappate alle colonne della tabella con lo stesso nome della proprietà.
Se si preferisce configurare le colonne con nomi diversi, è possibile farlo come frammento di codice seguente:
public class Blog
{
[Column("blog_id")]
public int BlogId { get; set; }
public string Url { get; set; }
}
Tipi di dati della colonna
Quando si usa un database relazionale, il provider di database seleziona un tipo di dati in base al tipo .NET della proprietà. Tiene anche conto di altri metadati, come la lunghezza massima configurata, se la proprietà fa parte di una chiave primaria e così via.
Ad esempio, il provider SQL Server esegue il mapping delle proprietà DateTime
alle colonne datetime2(7)
e delle proprietà string
alle colonne nvarchar(max)
(o alle colonne nvarchar(450)
per le proprietà usate come chiave).
È anche possibile configurare le colonne per specificare un tipo di dati esatto per una colonna. Ad esempio, il codice seguente configura Url
come stringa non Unicode con lunghezza massima di 200
e Rating
come decimale con precisione di 5
e scala di 2
:
public class Blog
{
public int BlogId { get; set; }
[Column(TypeName = "varchar(200)")]
public string Url { get; set; }
[Column(TypeName = "decimal(5, 2)")]
public decimal Rating { get; set; }
}
Lunghezza massima
La configurazione di una lunghezza massima fornisce un suggerimento al provider di database sul tipo di dati della colonna appropriato da scegliere per una determinata proprietà. La lunghezza massima si applica solo ai tipi di dati della matrice, ad esempio string
e byte[]
.
Nota
Entity Framework non esegue alcuna convalida della lunghezza massima prima di passare i dati al provider. Spetta al provider o all'archivio dati convalidare se appropriato. Ad esempio, quando la destinazione è SQL Server, il superamento della lunghezza massima genererà un'eccezione perché il tipo di dati della colonna sottostante non consentirà l'archiviazione dei dati in eccesso.
Nell'esempio seguente, la configurazione di una lunghezza massima di 500 causerà la creazione di una colonna di tipo nvarchar(500)
in SQL Server:
public class Blog
{
public int BlogId { get; set; }
[MaxLength(500)]
public string Url { get; set; }
}
Precisione e scala
Alcuni tipi di dati relazionali supportano i facet di precisione e scala; questi controllano i valori che è possibile archiviare e la quantità di spazio di archiviazione necessaria per la colonna. I tipi di dati che supportano la precisione e la scala dipendono dal database, ma nella maggior parte dei database i tipi decimal
e DateTime
supportano questi aspetti. Per le proprietà decimal
, la precisione definisce il numero massimo di cifre necessarie per esprimere qualsiasi valore contenuto nella colonna, mentre la scala definisce il numero massimo di posizioni decimali necessarie. Per le proprietà DateTime
, la precisione definisce il numero massimo di cifre necessarie per esprimere frazioni di secondi e la scala non viene utilizzata.
Nota
Entity Framework non esegue alcuna convalida della precisione o della scalabilità prima di passare i dati al provider. Spetta al provider o all'archivio dati convalidare in base alle esigenze. Ad esempio, quando la destinazione è SQL Server, una colonna di tipo di dati datetime
non consente di impostare la precisione, mentre una datetime2
può avere precisione compresa tra 0 e 7 inclusi.
Nell'esempio seguente, la configurazione della proprietà Score
in modo che abbia precisione 14 e scala 2 causerà la creazione di una colonna di tipo decimal(14,2)
in SQL Server e la configurazione della proprietà LastUpdated
in modo che la precisione 3 provocherà una colonna di tipo datetime2(3)
:
public class Blog
{
public int BlogId { get; set; }
[Precision(14, 2)]
public decimal Score { get; set; }
[Precision(3)]
public DateTime LastUpdated { get; set; }
}
La scala non viene mai definita senza definire prima la precisione, quindi l'annotazione dati per la definizione della scala è [Precision(precision, scale)]
.
Unicode
In alcuni database relazionali esistono tipi diversi per rappresentare dati di testo Unicode e non Unicode. In SQL Server, ad esempio, nvarchar(x)
viene usato per rappresentare i dati Unicode in UTF-16, mentre varchar(x)
viene usato per rappresentare dati non Unicode (ma vedere le note sul supporto UTF-8 di SQL Server ). Per i database che non supportano questo concetto, la configurazione non ha alcun effetto.
Le proprietà di testo vengono configurate come Unicode per impostazione predefinita. È possibile configurare una colonna come non Unicode come segue:
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
[Unicode(false)]
[MaxLength(22)]
public string Isbn { get; set; }
}
Proprietà obbligatorie e facoltative
Una proprietà viene considerata facoltativa se è valida per contenere null
. Se null
non è un valore valido da assegnare a una proprietà, viene considerato una proprietà obbligatoria. Quando si esegue il mapping a uno schema di database relazionale, le proprietà necessarie vengono create come colonne non annullabili e le proprietà facoltative vengono create come colonne annullabili.
Convenzioni
Per convenzione, una proprietà il cui tipo .NET può contenere valori Null verrà configurata come facoltativa, mentre le proprietà il cui tipo .NET non può contenere null verranno configurate in base alle esigenze. Ad esempio, tutte le proprietà con tipi di valore .NET (int
, decimal
, bool
e così via) vengono configurate come obbligatorie e tutte le proprietà con tipi di valore .NET nullable (int?
, decimal?
, bool?
e così via) vengono configurate come facoltative.
In C# 8 è stata introdotta una nuova funzionalità denominata tipi di riferimento nullable (NRT), che consente di annotare i tipi di riferimento, indicando se è ammesso che contengano valori null o meno. Questa funzionalità è abilitata per impostazione predefinita nei nuovi modelli di progetto, ma rimane disabilitata nei progetti esistenti, a meno che non venga esplicitamente scelto. I tipi di riferimento nullable influiscono sul comportamento di EF Core nel modo seguente:
- Se i tipi di riferimento nullable sono disabilitati, tutte le proprietà con tipi di riferimento .NET vengono configurate come opzionali secondo convenzione (ad esempio
string
). - Se i tipi riferimento nullable sono abilitati, le proprietà verranno configurate in base alla nullabilità C# del loro tipo .NET:
string?
verrà configurato come facoltativo, mastring
verrà configurato come obbligatorio.
L'esempio seguente mostra un tipo di entità con proprietà obbligatorie e facoltative, con la funzionalità di riferimento nullable disabilitata e abilitata:
public class CustomerWithoutNullableReferenceTypes
{
public int Id { get; set; }
[Required] // Data annotations needed to configure as required
public string FirstName { get; set; }
[Required] // Data annotations needed to configure as required
public string LastName { get; set; }
public string MiddleName { get; set; } // Optional by convention
}
L'uso di tipi di riferimento nullable è consigliato perché trasferisce la nullabilità espressa nel codice C# al modello di EF Core e al database ed evita l'uso dell'API Fluent o delle Data Annotations per esprimere lo stesso concetto due volte.
Nota
Prestare attenzione quando si abilitano i tipi di riferimento annullabili in un progetto esistente: le proprietà precedentemente configurate come facoltative saranno ora configurate come obbligatorie, a meno che non siano esplicitamente annotate come annullabili. Quando si gestisce uno schema di database relazionale, è possibile che vengano generate migrazioni che modificano la nullabilità delle colonne del database.
Per ulteriori informazioni sui tipi di riferimento nullable e su come usarli con EF Core, consulta la pagina della documentazione dedicata a questa funzionalità.
Configurazione esplicita
Una proprietà facoltativa per convenzione può essere configurata in modo che sia necessaria come indicato di seguito:
public class Blog
{
public int BlogId { get; set; }
[Required]
public string Url { get; set; }
}
Regole di confronto delle colonne
È possibile definire regole di confronto sulle colonne di testo, determinando il modo in cui vengono confrontate e ordinate. Ad esempio, il frammento di codice seguente configura una colonna di SQL Server senza distinzione tra maiuscole e minuscole:
modelBuilder.Entity<Customer>().Property(c => c.Name)
.UseCollation("SQL_Latin1_General_CP1_CI_AS");
Se tutte le colonne di un database devono usare determinate regole di confronto, definire invece le regole di confronto a livello di database.
Informazioni generali sul supporto di EF Core per le regole di confronto sono disponibili nella pagina della documentazione delle regole di confronto .
I commenti delle colonne
È possibile impostare un commento di testo arbitrario che viene impostato sulla colonna del database, consentendo di documentare lo schema nel database:
public class Blog
{
public int BlogId { get; set; }
[Comment("The URL of the blog")]
public string Url { get; set; }
}
Ordine delle colonne
Per impostazione predefinita, quando si crea una tabella con Migrazioni, EF Core ordina prima le colonne della chiave primaria, seguite dalle proprietà del tipo di entità e dei tipi di proprietà posseduti e infine dalle proprietà dai tipi base. È tuttavia possibile specificare un ordine di colonna diverso:
public class EntityBase
{
[Column(Order = 0)]
public int Id { get; set; }
}
public class PersonBase : EntityBase
{
[Column(Order = 1)]
public string FirstName { get; set; }
[Column(Order = 2)]
public string LastName { get; set; }
}
public class Employee : PersonBase
{
public string Department { get; set; }
public decimal AnnualSalary { get; set; }
}
L'API Fluent può essere usata per eseguire l'override dell'ordinamento eseguito con attributi, inclusa la risoluzione di eventuali conflitti quando gli attributi in proprietà diverse specificano lo stesso numero di ordine.
Si noti che, nel caso generale, la maggior parte dei database supporta solo l'ordinamento delle colonne al momento della creazione della tabella. Ciò significa che l'attributo dell'ordine di colonna non può essere usato per riordinare le colonne in una tabella esistente.