diff --git a/content/efcore/README.md b/content/efcore/README.md new file mode 100644 index 0000000..79bdd5d --- /dev/null +++ b/content/efcore/README.md @@ -0,0 +1,4 @@ +# Entity Framework Core Tutorials + +[Getting Started with Entity Framework Core](getting-started/README.md) +This tutorial covers the basics of using Entity Framework Core in a C# application. \ No newline at end of file diff --git a/content/efcore/getting-started/README.md b/content/efcore/getting-started/README.md new file mode 100644 index 0000000..3ba7914 --- /dev/null +++ b/content/efcore/getting-started/README.md @@ -0,0 +1,18 @@ +# Getting Started with Entity Framework Core + +## Who Should Read This + +This tutorial is aimed at people who are learning EF Core for the first time. More advanced functionality is covered in the [docs](https://docs.microsoft.com/en-us/ef/). Before beginning this tutorial, you should understand the following topics: + +- C# (see [Getting Started with C#](https://www.microsoft.com/net/tutorials/csharp/getting-started)) +- Relational database concepts +- LINQ (see [Introducing LINQ](https://www.microsoft.com/net/tutorials/csharp/getting-started/linq)) + + +## Topics Covered + +This tutorial will cover the following topics: + +- [Intro to EF Core](intro-to-ef-core.md) +- [Installing EF Core](installing-ef-core.md) +- [Querying Data](querying.md) diff --git a/content/efcore/getting-started/installing-ef-core.md b/content/efcore/getting-started/installing-ef-core.md new file mode 100644 index 0000000..2e90330 --- /dev/null +++ b/content/efcore/getting-started/installing-ef-core.md @@ -0,0 +1,56 @@ +# Installing EF Core + +In this lesson, you will learn how to install EF Core on your machine. You do not need to complete these steps to continue with the rest of the tutorial as the code examples in the other lessons are executable in-browser. + +## Install .NET Core + +If you haven't already, you will first need to install .NET Core on your machine. Go to the [.NET Core Page](https://www.microsoft.com/net/core) of the Microsoft website, and follow the installation instructions for your platform of choice. You can ensure .NET Core is installed by running the following command: + +``` +dotnet --version +``` + +## Create New Project + +Create a new project by running the following commands (you can skip these steps if you want to add EF Core to an existing project): + +``` +mkdir MyEfCoreProject # Create directory for project +cd MyEfCoreProject # Navigate to project directory +dotnet new # Initialize .NET Core project (generates Startup.cs and project.json) +``` + +## Add EF Core to Project + +To add EF Core to your project, you need to list it as a dependency in your `project.json` file. You need to add the appropriate package for your database provider as well. See [Database Providers](https://docs.microsoft.com/en-us/ef/core/providers/) in the docs for a full listing of available database providers. In this example, we use Sqlite. + +```{json} +"dependencies": { + "Microsoft.EntityFrameworkCore.Sqlite": "1.0.0", + "Microsoft.EntityFrameworkCore.Design": { + "version": "1.0.0-preview2-final", + "type": "build" + } +} +``` + +To add EF Core functionality to the [.NET Core Command-Line Interface](https://docs.microsoft.com/en-us/dotnet/articles/core/tools/), you need to add a package to the `tools` section of `project.json`: + +``` +"tools": { + "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final" +} +``` + +Once you have updated `package.json`, run the following command to install your project's tools and dependencies: + +``` +dotnet restore +``` + +After running this command, EF Core should be installed on your machine. You can run the following command to ensure EF Core was installed correctly: + +``` +dotnet ef --help +``` + diff --git a/content/efcore/getting-started/intro-to-ef-core.md b/content/efcore/getting-started/intro-to-ef-core.md new file mode 100644 index 0000000..510c446 --- /dev/null +++ b/content/efcore/getting-started/intro-to-ef-core.md @@ -0,0 +1,9 @@ +# Intro to EF Core + +Entity Framework Core (EF Core) is a lightweight, extensible, and cross-platform version of Entity Framework. Entity Framework is an object-relational mapper (O/RM) that enables .NET developers to work with a database using .NET objects. This allows developers to create and manage databases without most of the data-access code that developers usually need to write.  + +EF Core and the latest version of Entity Framework (EF6.x) differ in the features they support. A comparison of the features supported by each can be found on the [feature comparison page](https://docs.microsoft.com/en-us/ef/efcore-and-ef6/features) of the docs. If you want help determining which version is best for your project, check out the ["Which One Is Right for You?"](https://docs.microsoft.com/en-us/ef/efcore-and-ef6/choosing) page. + +## Database Providers + +At the moment, EF Core only supports relational databases, but there are plans to add support for non-relational databases in the future. Supported database providers are listed on the [Database Providers page](https://docs.microsoft.com/en-us/ef/core/providers/) in the docs. diff --git a/content/efcore/getting-started/querying.md b/content/efcore/getting-started/querying.md new file mode 100644 index 0000000..63295b5 --- /dev/null +++ b/content/efcore/getting-started/querying.md @@ -0,0 +1,96 @@ +# Querying Data + +In this lesson, you'll learn how to use querying to fetch one or more items from your database. EF Core uses LINQ to query data, so it is important that you understand LINQ before going through this lesson. Check out the [LINQ lesson](../../csharp/getting-started/linq.md) in the C# Interactive Tutorial if you need a refresher. + +## Example database + +For this lesson, we will use a small database to allow you to try querying on your own. The database has two tables, Books and Authors, and the data is as follows: + +### Books +| BookId | AuthorId | Title | Genre | PublicationYear | +|--------|----------|---------------------------------|------------------|-----------------| +| 1 | 9 | Mrs. Dalloway | Literary | 1925 | +| 2 | 6 | The Mysterious Island | Science Fiction | 1874 | +| 3 | 7 | The Blazing World | Science Fiction | 1666 | +| 4 | 1 | The Scarlet Plague | Science Fiction | 1912 | +| 5 | 8 | The Secret Adversary | Mystery | 1922 | +| 6 | 6 | An Antarctic Mystery | Mystery | 1897 | +| 7 | 5 | My Bondage and My Freedom | Narrative | 1855 | +| 8 | 3 | The Count of Monte Cristo | Adventure | 1845 | +| 9 | 10 | Minnie's Sacrifice | Historical | 1869 | +| 10 | 4 | My Antonia | Historical | 1918 | +| 11 | 4 | O Pioneers! | Historical | 1913 | +| 12 | 2 | Adventures of Huckleberry Finn | Satire | 1884 | +| 13 | 2 | The Adventures of Tom Sawyer | Satire | 1876 | +| 14 | 10 | Iola Leroy | Historical | 1892 | +| 15 | 8 | Murder on the Orient Express | Mystery | 1934 | +| 16 | 1 | The Call of the Wild | Adventure | 1903 | +| 17 | 4 | Death Comes for the Archbishop | Historical | 1927 | + + +### Authors +| AuthorId | FirstName | LastName | +|----------|------------|-----------| +| 1 | Jack | London | +| 2 | Mark | Twain | +| 3 | Alexandre | Dumas | +| 4 | Willa | Cather | +| 5 | Frederick | Douglass | +| 6 | Jules | Vern | +| 7 | Margaret | Cavendish | +| 8 | Agatha | Christie | +| 9 | Virginia | Woolf | +| 10 | Frances | Harper | +| 11 | Stephen | Crane | + +## Loading All Entities + +Let's say we want to get all of the books from our database in a C# application. Normally, we would have to write a database query in a domain-specific language, such as SQL, and then we would have to manually map the results of this query to C# objects. With EF Core, this process is much easier because it takes care of the data access code for us. + +```{.snippet} +using (var context = new LibraryContext()) +{ + var books = context.Books.ToList(); +} +``` +:::repl{data-name=loading-all-entities} +::: + +In order to interact with the database via EF Core, we must first create an instance of our context (`LibraryContext`). Notice that we create the context with the `using` keyword. This automatically disposes the context after the using block has finished executing. Alternatively, we could manually call `LibraryContext.dispose()`, but the `using` method is more convenient and readable. It is imperative that we dispose of the context after we are finished using it because it holds an open connection to the database. + +Once we have an instance of the context, we can use it to interact with the database. To access the books in the database, we reference the relevant `DbSet` within the context - `Books` in our case - and call the `ToList` method to convert the `DbSet` to a `List`. The resulting list will contain all of the books within the database. + +## Filtering Entities + +Loading all of the entities from a database is useful, but there are many use cases where we only want to load a subset of the entities from the database. For example, we may want to filter books by author or genre. EF Core allows us to filter entities via the `Where` extension method. Let's look at an example where we retrieve all Historical books from the database. + +```{.snippet} +using (var context = new LibraryContext()) +{ + var books = context.Books + .Where(b => b.Genre == "Historical") + .ToList(); +} +``` +:::repl{data-name=filtering-entities} +::: + +We use a lambda expression within the `Where` method to detect if the `Genre` property of each book is equal to "Historical". Books that meet the criteria of the lambda expression will be included in the final result, while books that do not will be excluded. + +We could retrieve all of the books like in the previous example and then filter them in our application; however, this would require us to load all of the books into memory, and it does not allow us to take advantage of our database's optimized querying functionality. Allowing the database to do what it does best and perform the filtering for us results in a significant performance increase. Thus, it is important that we filter the `DbSet` with the `Where` method before calling `ToList`. + +## Loading a Single Entity + +Both of our examples so far have shown how to retrieve a collection of entities. Let's look at how to retrieve a single entity based on a unique identifier. + +```{.snippet} +using (var context = new LibraryContext()) +{ + var book = context.Books + .Single(b => b.Id == 1); +} +``` +:::repl{data-name=loading-single-entity} +::: + +In this example, we use the `Single` extension method to find the book with an `Id` of 1. Note that we do not need to call `ToList()` because `Single` returns a single entity. It is important to only use `Single` with unique identifiers because if multiple entities meet the success criteria a `System.InvalidOperationException` will be thrown. diff --git a/content/efcore/getting-started/samples/filtering-entities/Program.cs b/content/efcore/getting-started/samples/filtering-entities/Program.cs new file mode 100644 index 0000000..1e05ed9 --- /dev/null +++ b/content/efcore/getting-started/samples/filtering-entities/Program.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +public class Program +{ + public static void Main() + { + using (var context = new LibraryContext()) + { + var books = context.Books + .Where(b => b.Genre == "Historical") + .ToList(); + + foreach (Book book in books) + { + Console.WriteLine(String.Format("{0} - {1}", book.Title, book.Genre)); + } + } + } +} \ No newline at end of file diff --git a/content/efcore/getting-started/samples/filtering-entities/README.md b/content/efcore/getting-started/samples/filtering-entities/README.md new file mode 100644 index 0000000..2cefbae --- /dev/null +++ b/content/efcore/getting-started/samples/filtering-entities/README.md @@ -0,0 +1,9 @@ +# Filtering Entities + +This code example demonstrates how to use EF Core to query a subset of entities from the database based on specified filters. + +## Code Files: +- [Program.cs](Program.cs) +- [LibraryContext.cs](../shared/LibraryContext.cs) +- [Book.cs](../shared/Book.cs) +- [Author.cs](../shared/Author.cs) \ No newline at end of file diff --git a/content/efcore/getting-started/samples/loading-all-entities/Program.cs b/content/efcore/getting-started/samples/loading-all-entities/Program.cs new file mode 100644 index 0000000..3106389 --- /dev/null +++ b/content/efcore/getting-started/samples/loading-all-entities/Program.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +public class Program +{ + public static void Main() + { + using (var context = new LibraryContext()) + { + var books = context.Books.ToList(); + foreach (Book book in books) + { + Console.WriteLine(book.Title); + } + } + } +} \ No newline at end of file diff --git a/content/efcore/getting-started/samples/loading-all-entities/README.md b/content/efcore/getting-started/samples/loading-all-entities/README.md new file mode 100644 index 0000000..35b8f2b --- /dev/null +++ b/content/efcore/getting-started/samples/loading-all-entities/README.md @@ -0,0 +1,9 @@ +# Loading All Entities + +This code example demonstrates how to use EF Core to query all entities from the database. + +## Code Files: +- [Program.cs](Program.cs) +- [LibraryContext.cs](../shared/LibraryContext.cs) +- [Book.cs](../shared/Book.cs) +- [Author.cs](../shared/Author.cs) \ No newline at end of file diff --git a/content/efcore/getting-started/samples/loading-single-entity/Program.cs b/content/efcore/getting-started/samples/loading-single-entity/Program.cs new file mode 100644 index 0000000..c0a1c52 --- /dev/null +++ b/content/efcore/getting-started/samples/loading-single-entity/Program.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +public class Program +{ + public static void Main() + { + using (var context = new LibraryContext()) + { + var book = context.Books + .Single(b => b.BookId == 1); + Console.WriteLine(book.Title); + } + } +} \ No newline at end of file diff --git a/content/efcore/getting-started/samples/loading-single-entity/README.md b/content/efcore/getting-started/samples/loading-single-entity/README.md new file mode 100644 index 0000000..59c4aa7 --- /dev/null +++ b/content/efcore/getting-started/samples/loading-single-entity/README.md @@ -0,0 +1,9 @@ +# Loading A Single Entity + +This code example demonstrates how to use EF Core to query a single entity from the database. + +## Code Files: +- [Program.cs](Program.cs) +- [LibraryContext.cs](../shared/LibraryContext.cs) +- [Book.cs](../shared/Book.cs) +- [Author.cs](../shared/Author.cs) \ No newline at end of file diff --git a/content/efcore/getting-started/samples/shared/Author.cs b/content/efcore/getting-started/samples/shared/Author.cs new file mode 100644 index 0000000..8bd1c6a --- /dev/null +++ b/content/efcore/getting-started/samples/shared/Author.cs @@ -0,0 +1,6 @@ +public class Author +{ + public int AuthorId { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } +} \ No newline at end of file diff --git a/content/efcore/getting-started/samples/shared/Book.cs b/content/efcore/getting-started/samples/shared/Book.cs new file mode 100644 index 0000000..01e5070 --- /dev/null +++ b/content/efcore/getting-started/samples/shared/Book.cs @@ -0,0 +1,9 @@ +public class Book +{ + public int BookId { get; set; } + public string Title { get; set; } + public string Genre { get; set; } + public int PublicationYear { get; set; } + + public Author Author { get; set; } +} \ No newline at end of file diff --git a/content/efcore/getting-started/samples/shared/LibraryContext.cs b/content/efcore/getting-started/samples/shared/LibraryContext.cs new file mode 100644 index 0000000..4c169bf --- /dev/null +++ b/content/efcore/getting-started/samples/shared/LibraryContext.cs @@ -0,0 +1,14 @@ +using Microsoft.EntityFrameworkCore; +using System.Collections.Generic; +using REPLHelper; + +public class LibraryContext : DbContext +{ + public DbSet Books { get; set; } + public DbSet Authors { get; set; } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + optionsBuilder.UseSqlite(DBHelper.GetReadonlyDbConnectionString()); + } +} \ No newline at end of file diff --git a/content/efcore/getting-started/toc.md b/content/efcore/getting-started/toc.md new file mode 100644 index 0000000..117193c --- /dev/null +++ b/content/efcore/getting-started/toc.md @@ -0,0 +1,3 @@ +- [Intro to EF Core](intro-to-ef-core.md) +- [Installing EF Core](installing-ef-core.md) +- [Querying Data](querying.md) \ No newline at end of file