Detail Queries9:35 with James Churchill
Now that we've seen some examples of LINQ queries that return lists of records, let's take a look at queries that are designed to return a single entity.
To follow along commiting your changes to this course, you'll need to fork the dotnet-comic-book-gallery-model repo. Then you can clone, commit, and push your changes to your fork like this:
git clone <your-fork> cd dotnet-comic-book-gallery-model git checkout tags/v4.5 -b detail-queries
Now that we've seen some examples of linq queries that return lists of records, 0:00 let's take a look at queries that are designed to return a single entity. 0:04 If you're following along, let's start by commenting out this existing code. 0:08 I'll select everything, starting just below where we're setting the database log 0:14 property, down to but not including the Console.ReadLine method call. 0:19 One of the simplest ways to retrieve a single entity, 0:26 is to use the DbSet's Find method. 0:29 First, let's add a variable for our comicBook ID value. 0:32 var comicBookId = 1. 0:36 Then let's run our query. 0:42 var comicBook = 0:44 context.ComicBooks.Find(comicBookID). 0:47 The Find method will check if the entity is already being tracked by the context 0:55 and if it is, return a reference to that entity. 1:00 Otherwise, it will retrieve the entity from the database. 1:03 We can test that behavior by making a second call to the Find method. 1:07 Rename the comicBook variable to comicBook1. 1:11 And add a second call to the Find method, 1:18 var comicBook2 = context.ComicBooks.Find(comicBookId);. 1:23 This will allow us to check if a query was generated for the second call and 1:32 whether or not the returned comicBook objects are in fact the same object. 1:37 Let's set a breakpoint on the line of code containing the first call to the Find 1:42 method, and run the app. 1:46 Now we're at our breakpoint. 1:56 Press F10 to execute the Find method call. 1:58 In the output window, 2:03 we can see the query that was executed to retrieve the comic book entity. 2:04 Press F10 again to execute the second call to the Find method. 2:18 Notice that another query did not get generated or executed. 2:28 We can use the immediate window to compare the comicBook1 and comicBook2 variables. 2:32 comicBook1 == comicBook2. 2:37 Comparing the two objects returns true which tells us that the variables 2:44 are in fact references to the same object. 2:49 Now, let's look at an example of retrieving an entity using a DbSet query. 3:05 var comicBook = context.comicBooks. 3:11 We can use the Where operator to filter the results down to a single comic 3:18 book ID. 3:23 .Where(cb => cb.Id = comicBookId). 3:24 And then instead of calling the ToList method to execute the query, 3:34 we can use the SingleOrDefault method, .SingleOrDefault();. 3:38 The SingleOrDefault method will return a single entity or null depending on 3:44 whether or not a comic book is found that matches the provided filter criteria. 3:49 If more than one entity is found, the method will throw an exception. 3:54 This is the difference between the SingleOrDefault and 4:02 FirstOrDefault operators. 4:05 The former enforces that a single entity is found, 4:08 while the latter simply returns the first entity if more than one is found. 4:11 The Single and First operators go a step further and enforce that at least one 4:18 entity is found by throwing an exception if no matching entities are found. 4:23 We can simplify our query by moving our filter criteria from 4:28 the Where operator down to the SingleOrDefault operator. 4:31 For testing purposes, let's make a copy of the queries so 4:43 we can compare the behavior of a DbSet query to the Find method. 4:47 Set a breakpoint on the first query and run the app. 4:52 Press F10 to execute the first query. 5:01 In the output window, we can see the query. 5:15 Press F10 again, And in the output window, we can see the second query. 5:18 Switching to the immediate window. 5:33 Let's compare the comicBook1 and comicBook2 variables again. 5:35 comicBook1 == comicBook2. 5:40 Okay, so the variables reference the same object, but 5:45 a query was generated and executed against the database for each of our linq queries. 5:49 This seems to indicate that DbSet queries 5:54 always result in a query being generated and executed against the database. 5:57 Even though the same entity object instance is being returned from both 6:02 queries. 6:06 Let's run another test. 6:12 This time, let's modify the entity that is being returned from the first query. 6:14 Then, we'll inspect the entity that is being returned from the second query. 6:19 comicBook1, and then let's change the description. 6:24 .Description = "New value!";. 6:28 Let's also add a Debug.WriteLine method call, so 6:35 we can see when we change the description property value. 6:38 Debug.WriteLine, ("Changing 6:42 the Description property value."); 6:48 Okay, we're at our breakpoint again. 6:58 Press F10 to execute the first query. 7:01 Then again to modify the Description property, and 7:06 one more time to execute the second query. 7:11 In the output window, we can see the first query. 7:24 Then, our Debug.WriteLine method call and the second query. 7:31 So two queries were generated and executed, 7:38 one before we changed the description property and one after the change. 7:41 If we review the comicBook2 variable in the Locals window, 7:52 we can see that the entity's description property still has our New value. 7:55 This tells us that the data retrieved by the second query was ignored by EF, 8:00 because the entity was already in the context. 8:05 While this behavior might seem odd at first glance, 8:10 it actually helps ensure that entities that have been modified 8:14 don't accidentally lose their unsaved values. 8:17 If when a query is executed that retrieves the entity's data again from the database. 8:20 Another thing to note about DbSet queries is that they can't be used to retrieve 8:26 entities from the contexts that have been added using the DbSet Add method but 8:30 haven't been persisted yet to the database. 8:36 To retrieve unsaved new entities from the context, 8:39 you need to use the DbSet Find method. 8:42 In advantage the DbSet queries have over the Find method is that 8:45 you can eagerly load related entities 8:49 Because of this, I prefer to use DbSet queries to retrieve single entities 8:58 over using the Find method. 9:02 Let's review this section. 9:06 We saw how to use linq entities to write, filter and sort queries. 9:08 We also learned about the pros and 9:13 cons of eagerly, lazily and explicitly loading related entities. 9:14 Lastly, we saw examples of how to retrieve single entities. 9:19 In the last section of this course, we'll see how to use the EF context to perform 9:24 the remaining three CRUD operations: create, update and delete. 9:28 See you in a bit. 9:33
You need to sign up for Treehouse in order to download course files.Sign up