Proprietà 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, 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 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; }
}
Tipo di dati colonna
Quando si usa un database relazionale, il provider di database seleziona un tipo di dati in base al tipo .NET della proprietà. Tiene conto anche di altri metadati, ad esempio la lunghezza massima configurata, se la proprietà fa parte di una chiave primaria e così via.
Ad esempio, SQL Server esegue il mapping DateTime
delle proprietà alle datetime2(7)
colonne e string
alle proprietà alle nvarchar(max)
colonne (o a 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 viene configurato Url
come stringa non Unicode con lunghezza massima e 200
Rating
come decimale con precisione 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 di 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 scalabilità dipendono dal database, ma nella maggior parte dei database decimal
e DateTime
dei tipi supportano questi facet. Per decimal
le proprietà, precisione definisce il numero massimo di cifre necessarie per esprimere qualsiasi valore che la colonna conterrà e la scala definisce il numero massimo di cifre decimali necessarie. Per DateTime
le proprietà, 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 datetime
dati non consente l'impostazione della precisione, mentre una datetime2
può avere una precisione compresa tra 0 e 7 inclusi.
Nell'esempio seguente, la configurazione della Score
proprietà 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 LastUpdated
proprietà con precisione 3 causerà 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 come una proprietà obbligatoria. Quando si esegue il mapping a uno schema di database relazionale, le proprietà necessarie vengono create come colonne non nullable e le proprietà facoltative vengono create come colonne nullable.
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 valore .NET (int
, decimal
, bool
e così via) vengono configurate come obbligatorie e tutte le proprietà con tipi valore .NET nullable (int?
, decimal?
, bool?
e così via) vengono configurate come facoltative.
In C# 8 è stata introdotta una nuova funzionalità denominata NRT (Nullable Reference Types), che consente l'annotazione dei tipi riferimento, che indica se è valida per contenere 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 riferimento nullable influiscono sul comportamento di EF Core nel modo seguente:
- Se i tipi riferimento nullable sono disabilitati, tutte le proprietà con i tipi riferimento .NET vengono configurate come facoltative per convenzione , ad esempio
string
. - Se i tipi riferimento nullable sono abilitati, le proprietà verranno configurate in base al supporto null di C# del tipo .NET:
string?
verrà configurato come facoltativo, mastring
verrà configurato come richiesto.
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 riferimento nullable è consigliato perché passa il valore Nullbility espresso nel codice C# al modello di EF Core e al database e obvia l'uso dell'API Fluent o delle annotazioni dei dati per esprimere lo stesso concetto due volte.
Nota
Prestare attenzione quando si abilitano i tipi riferimento nullable in un progetto esistente: le proprietà del tipo di riferimento configurate in precedenza come facoltative verranno ora configurate come obbligatorie, a meno che non siano annotate in modo esplicito come nullable. Quando si gestisce uno schema di database relazionale, è possibile che vengano generate migrazioni che modificano il supporto dei valori Null della colonna di database.
Per altre informazioni sui tipi di riferimento nullable e su come usarli con EF Core, vedere la pagina della documentazione dedicata per 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.
Commenti colonna
È 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 chiave primaria, seguite dalle proprietà del tipo di entità e dei tipi di proprietà e infine dalle proprietà dei tipi di 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.