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 200Rating 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, boole 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, ma string 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.