Skip to content

Commit

Permalink
Improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
roji committed Sep 23, 2019
1 parent c20799a commit 933d29e
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 14 deletions.
10 changes: 3 additions & 7 deletions entity-framework/core/miscellaneous/nullable-reference-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,7 @@ This page introduces EF Core's support fo nullable reference types, and describe

## Required and optional properties

If nullable reference types are enabled, EF Core will by convention configure reference properties as required or optional based on their C# type nullability. For example, properties with type `string` will be configured as required, while properties with type `string?` will be configured as optional.

[!code-csharp[Main](../../../samples/core/Miscellaneous/NullableReferenceTypes/Customer.cs?name=Customer&highlight=4-6)]

Using nullable reference types is recommended since it flows the nullability expressed in C# code to EF Core's model and to the database, and obviates the use of the Fluent API or Data Annotations to express the same concept twice.
The main documentation on required and optional properties and their interaction with nullable reference types is the [Required and Optional Properties](xref:core/modeling/required-optional) page. It is recommended you start out by reading that page first.

> [!NOTE]
> Exercise caution when enabling nullable reference types on an existing project: reference type properties which were previously configured as optional will now be configured as required, unless they are explicitly annotated to be nullable. When managing a relational database schema, this may cause migrations to be generated which alter the database column's nullability.
Expand All @@ -36,13 +32,13 @@ Required navigation properties present an additional difficulty: although a depe

One way to deal with these scenarios, is to have a non-nullable property with a nullable [backing field](xref:core/modeling/backing-field):

[!code-csharp[Main](../../../samples/core/Miscellaneous/NullableReferenceTypes/Order.cs?name=Order&highlight=16-11)]
[!code-csharp[Main](../../../samples/core/Miscellaneous/NullableReferenceTypes/Order.cs?name=Order&highlight=7-12)]

Since the navigation property is non-nullable, a required navigation is configured; and as long as the navigation is properly loaded, the dependent will be accessible via the property. If, however, the property is accessed without first properly loading the related entity, an InvalidOperationException is thrown, since the API contract has been used incorrectly.

As a terser alternative, it is possible to simply initialize the property to null with the help of the null-forgiving operator (!):

[!code-csharp[Main](../../../samples/core/Miscellaneous/NullableReferenceTypes/Order.cs?name=Order&highlight=13)]
[!code-csharp[Main](../../../samples/core/Miscellaneous/NullableReferenceTypes/Order.cs?name=Order&highlight=14)]

An actual null value will never be observed except as a result of a programming bug, e.g. accessing the navigation property without properly loading the related entity beforehand.

Expand Down
16 changes: 14 additions & 2 deletions entity-framework/core/modeling/required-optional.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Required/optional properties - EF Core
title: Required and Optional Properties - EF Core
author: rowanmiller
ms.date: 10/27/2016
ms.assetid: ddaa0a54-9f43-4c34-aae3-f95c96c69842
Expand All @@ -20,6 +20,18 @@ C# 8 introduced a new feature called [nullable reference types](/dotnet/csharp/t
* If nullable reference types are disabled (the default), all properties with .NET reference types are configured as optional by convention (e.g. `string`).
* If nullable reference types are enabled, properties will be configured based on the C# nullability of their .NET type: `string?` will be configured as optional, whereas `string` will be configured as required.

The following example shows an entity type with required and optional properties, with the nullable reference feature disabled (the default) and enabled:

# [Without nullable reference types](#tab/without-nrt)

[!code-csharp[Main](../../../samples/core/Miscellaneous/NullableReferenceTypes/CustomerWithoutNullableReferenceTypes.cs?highlight=10-14)]

# [With nullable reference types](#tab/with-nrt)

[!code-csharp[Main](../../../samples/core/Miscellaneous/NullableReferenceTypes/Customer.cs?name=Customer&highlight=4-6)]

***

Using nullable reference types is recommended since it flows the nullability expressed in C# code to EF Core's model and to the database, and obviates the use of the Fluent API or Data Annotations to express the same concept twice.

> [!NOTE]
Expand All @@ -29,7 +41,7 @@ For more information on nullable reference types and how to use them with EF Cor

## Configuration

You can indicate that a property is required as follows:
A property that would be optional by convention can be configured to be required as follows:

# [Data Annotations](#tab/data-annotations)

Expand Down
2 changes: 1 addition & 1 deletion entity-framework/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
href: core/modeling/keys.md
- name: Generated Values
href: core/modeling/generated-properties.md
- name: Required/optional properties
- name: Required and Optional Properties
href: core/modeling/required-optional.md
- name: Maximum Length
href: core/modeling/max-length.md
Expand Down
6 changes: 3 additions & 3 deletions samples/core/Miscellaneous/NullableReferenceTypes/Customer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
public class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string? MiddleName { get; set; }
public string FirstName { get; set; } // Required by convention
public string LastName { get; set; } // Required by convention
public string? MiddleName { get; set; } // Optional by convention

public Customer(string firstName, string lastName, string? middleName = null)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System.ComponentModel.DataAnnotations;

#nullable disable

namespace NullableReferenceTypes
{
public class CustomerWithoutNullableReferenceTypes
{
public int Id { get; set; }
[Required]
public string FirstName { get; set; } // Required by configuration
[Required]
public string LastName { get; set; } // Required by configuration
public string MiddleName { get; set; } // Optional by convention
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace NullableReferenceTypes
{
#region Context
#region Context
public class NullableReferenceTypesContext : DbContext
{
public DbSet<Customer> Customers { get; set; } = null!;
Expand Down

0 comments on commit 933d29e

Please sign in to comment.