Entity Framework Core Part 2

Apr 16, 2020 15:42 · 3617 words · 17 minute read changed business entity thing back

On today’s Visual Studio Toolbox, it’s Part 2 of our Entity Framework Core series. Phil Japikse shows change tracking and also explains an error we introduced in part 1 when we changed property names in the scaffolded code. [MUSIC]. >> Hi, welcome to Visual Studio Toolbox, I’m your host, Robert Green, and joining me is Phil Japikse. Hey, Phil. >> Hey, Robert. >> This is part 2 of our multi-part series on using Entity Framework Core and in part 1, we started with an existing SQL Server database and then Phil ran some scaffolding code, was one line of code which created classes for each of the tables and then took account of all of the relationships and all of the underlying goodness that was inside the database. >> Correct. >> Today, we’re going to actually now do stuff with that database and we’re going to see how we can start working with the actual data in an application, is that at a pretty good summary? >> It’s pretty good summary. >> Perfect.

01:07 - >> So we talked about dependency injection briefly on the last episode, and I want to just show it in action of how we can figure a DbContext. So DbContext itself doesn’t know it’s connection string, doesn’t have any knowledge of what provider to use, we have to tell it that. >> Sorry to interrupt, just to review, the DbContext is the connection between your app and the actual database essentially. >> I don’t want to use the word connection because it’s overloaded here, the DbContext is the master control program of EF core. >> It’s the general contractor, it’s the thing that you hired in the project of working with the data. >> Correct. So the DbContext we have to configure. >> I like that one.

You feel free 02:06 - to use it in future training courses. >> So DbContext factory has to be configured, so we have to give it a connection string, we also have to tell it what database provider to use. So in these examples, we’re using SQL Server, but there’s also an in-memory database which you can use for things like testing, you can set up Oracle, even Cosmos DB provider. So very simply, I have created a ContextFactory. I’m using it to create in code, it’s really designed for the command line interface.

02:40 - So the one line of code that we ran from the command line to create all these objects, when we do migrations going the other way, this is how we tell Entity Framework Core what to connect to, it’s really only meant to be used in design, but we’re using it in code for simplicity. But to show you how it works, we have a context options builder, we assign a connection string and we tell it what database provider we want to use. So we’re going to use SQL Server passing in the connection string and then we’ll cover these in greater detail in later episodes, but what I’m doing here is enabling a retry logic. So if the Internet is glitchy, it will retry up to five times and then I create a new instance of the DbContext. >> Now here’s a question before we move on, go back to that. >> Yeah.

03:40 - >> In real-world, how do you handle things like connection strings? I mean, obviously you shouldn’t be putting this type of information in your source code and then checking it into your repository. >> Correct. >> What do you like to use? >> So let me just clarify that a little bit. I’m okay checking this into my repository because this is not a production connection string, it’s only used in development because it’s the design-time factory. So with ASP.NET Core, there’s a very rich configuration ecosystem where based on the environment you’re running in; development, staging, production, made-up names, whatever, it’ll load at different configuration file. So for example, the app settings.production.

json file that would 04:40 - have all of their production values in it, we don’t ever have access to it as developers. That’s handled by the IT pros, all they have to do is put that file on the server, we never see it and it’s not checked into source control. Now that’s one way to do it or you can use Azure Key Vault on there’s, you can use Azure Active Directory, there’s various other ways to get that production information into your app, but from a Entity Framework Core perspective, it never sees the production connection string. So prior versions of Entity Framework, you had to have it in the app.config file, which meant every developer had access to it as well as source control, does that answer your question? >> Yeah. We did an episode on Azure Key Vault a while ago.

05:37 - So if you’re doing like a desktop app, WPF or UWP or something, then that would be a recommendation from you? >> Yeah, absolutely. So we use WPF for chart flow automation systems, and then we use EF Core with WPF as our data access layer and so the connection string is actually coming from a service and being injected into the application, so it’s not in the config file. >> Perfect, thanks. >> Again, I’m changing how [inaudible] factory is supposed to be used, I just want to clarify that because somebody’s going to watch it and say, “It’s only for design,” and you’re right, it’s for design and demo. So down here, I have newContextFactory CreateDbContext, it is a factory, so I’m using it. But again, I just want to stress it’s meant for design time and not for production like I’m doing.

06:42 - We should be injecting any information in, but I wanted to keep everything simple. What I want to talk about now in details is the change tracker and this is really the business value that I see the most from using an ORM in your application. So if we’re not using an ORM and we’re pulling data back, which we can do, [inaudible] stored procedures, you can use commands, connections, data adaptors, now you have data in your application, if somebody works with that data. But now we have to figure out how to persist those changes. So I have to track in my application, what fields changed? What records were added? What records were deleted? I’m doing all of that plumbing manually.

07:36 - Then when I want to save that, I have to write all that SQL very specific for those fields, for those objects to make sure I’m saving the right data. Is it complex? No, not at all, we can all do that. Is it a pain in the butt? Absolutely. >> So it’s plumbing. >> It’s plumbing, it’s time-consuming. So let’s talk about the change tracker. When we pull something from the database and we’ll talk about simple queries probably in a later episode depending on how far we get. We’re loading it into the DbSet as we explored on the last episode and when we pull it into the DB set, it gets added to the change tracker, but what a change tracker then does is basically wrap a proxy around that and say, “I’m going to track this particular instance.” So if you change a value, it will then know what the current value is of that object, but it also knows what the original value was.

08:42 - So what was the value when it got loaded into the DbSet? If you add a new object, we’ll then say, “Hey, this object has been added.” If you delete it, it’s been removed and it tracts all that for you and this is where to DbContext comes back into play as to master control program or the general contractor to use your analogy, but see if I use your analogy then I have to say and this Robert Green’s analogy every time. >> No, I give you permission to use it unattributed. >> Oh, okay. So it’s a [inaudible] >> It’s your payment for being on the show. >> So the general contractor then says, oh, okay, you want to, as a developer we call SaveChanges, and we’ll talk about the SaveChanges method in a later episode.

09:37 - But SaveChanges is the trigger point that says to the DbContext, let’s figure out what’s going on and let’s persist this data. So the change tracker then reports to the DbContext, here are all the objects I’m Tracking, here are the ones that have changed, and here’s what’s changed on them. So then the DbContext takes this information and talks to the database provider, in our example, the SQL Server provider, and then creates the SQL necessary to persist that data to the database. Now that’s all done for us automagically. So now we have all these changes wrapped up in a SQL core. The SaveChanges method by default is transactional.

10:27 - So I add three records, I delete two others, and I change six, and it can be across any table within the DbContext, I call save changes. What happens is a transaction gets opened, the SQL gets executed to do all those things that we’ve asked it to do. It checks to make sure that everything worked. If anything failed, then it will roll back the entire transaction, and if everything worked, it’ll commit the transaction, and then any server-side properties such as row version or ID, if it’s a sequence, will then get populated on those objects in the change tracker into DBSets, and now we have an updated set of values in our in memory objects matching those database table records is updated to match. >> Okay. >> So there’s a lot of heavy lifting going on that we don’t have to think about. >> Right.

11:34 - >> Does that make sense? >> Yeah. >> So if we look at just some very simple examples of how the change tracker works. So if I create a new instance of a person record, I am creating all the fields, it doesn’t matter. Then I can check the state of that object, and we can run this, but I’m not going to waste time running it. We’ll come back. Actually, you know what, this is easier to run, but it will come back and say, the edge run time dates, let’s run this one? >> Yeah, let’s run. >> Right. Yeah, we can run this. This is easy enough to run.

12:22 - So let me put a breakpoint here, and then run this. I just, I’m calling their run samples. So I have this new person, I’m getting this state of this, this is an interesting syntax because we haven’t added to DBSet yet, but I can say contexts, which is my DbContext entry, and it gets me to entity entry even though it’s not in the actual DBSet at this time. So if we want to, this is because Robert had me change the name. >> I tried. >> Awesome source. >> He didn’t change it to navigation. >> No, I didn’t. >> He didn’t change it everywhere? >> Well, I copied some code in as the problem. >> You can change it back if you want. >> No. I see what the problem is. This is actually good. Now, that I see what it’s doing, we can run with this error because what we did was we changed the names, we broke it, and I think this would be important to point out because other people are going to run into this if they follow along with the video. >> Okay. >> Though, I know how to fix it. >> Yeah, let’s run this.

13:59 - >> Interestingly enough, easy for me to say, we’re going to run into a problem here, but we’ll explain what that problem is in this because you had to be changed the names in the last episode, but it’s an important one to fix. >> Your code doesn’t work, it’s my fault. >> Absolutely, but I can use the general contractor terminals. You’re just going to take that back for me. >> No way. >> So we’re going to run into an issue when we try and read this entry, and the exception that we’re getting says the inverse property attribute is invalid. Now, what happened was actually picked up on this at the time, we were in the person object, and Robert and I both agree that we didn’t like the naming convention, and we changed business entity to business entity navigation, and we use business entity contacts instead of business entity contact.

14:56 - >> Because business entity contact or customer e-mail address is a collection, we said this should be pluraled or pluralized. >> Here’s one of the biggest problems with the way to scaffolding works. These inverse properties have to be strings, but the problem is that they’re magic strings in this point, and we’re not using the name of [inaudible]. So if we go to the business entity, you have to figure out which one it is. So I’m going to do, I’m going to change them back, and I’m going to show you how that you will want to fix them in the future because I don’t want to time on the video, but instead of doing, like here they use the name of the property.

15:49 - All of these should be the name of, so this should be name of business entity.business entity name navigation, or business entity.person. The reason they don’t do that is because of the name conflict here, which we talked about in the last episode. But I want to revert it so we can get the samples working, but I do want to point out that when you change the names, it has to be tilted all the way down. Otherwise you’re going to run into that problem when it tries to build that model.

Does that make sense? 16:24 - Like we’re referring to properties on other objects, but we changed this name. So I’d have to go through and every where there’s a business entity property referred to as a string, and I have to change it the business entity and navigation. >> Okay. >> That would just be a lot of work. Yes, it’s important to do, but not for this show. >> Okay. >> So let’s run it. Now that we’ve reverted, then we’ve broken all other things, awesome. >> This is scaffolding. >> This is scaffolding code because I used to built-in renamed function. >> Yeah.

17:12 - >> But when I just renamed them back, I didn’t used to built-in rename function. >> Okay. So that’s a good learn. If you’re going to change the code, the scaffolding built, be careful. >> Yeah, and I recommend cleaning it up if you’re going to continue using the scaffolding, but what a lot of people will do is they’ll start with scaffolding, and then move to more of a code centric approach from there, looking forward, and let’s make sure that we haven’t broken it again. Here is the advantage of having the scaffolding in place. I can go back to my command prompt here, and I can nuke everything that I have. >> Again. Okay. >> So can I share to do –force. Maybe it’s -force.

18:26 - So we have just overwritten all of that screen with the renamed stuff that we did in the last episode. >> It seemed like such a good idea at the time. >> It is a good idea, just not when you have a 20 minute episode. >> Okay. >> All right. So now, we’re going to get the entity entry, which is what an object in the DbContext land is referred to, and we’re going to get the state. If I just run this to the end, the first state is detached. That is, it’s not in a DbSet. We haven’t added it in.

19:08 - Then, when we add it in, and let me just get to a code to match up here. So here, we have our new object. It’s not in a DbSet, it is in a detached state. When we do a simple query and we say get me the data from the database, and then I can line these up like this. So if I pull one back, it’s unchanged. If I add it, it’s added, if I remove, it is deleted, and then if I change a property, it’s modified, and then when I change a property and I get a modified result, I can actually go through and on that entity entry, I can get to properties that are modified, and then display the original property value as well as the current value. So this change tracking, does other a couple of things.

20:14 - The goodness is as we’ve discussed, it’s keeping track of everything that we want to have changed. The badness is that it’s keeping track of everything that we want to have changed. What I mean by that is, if you have an item that has 200 properties, and we can discuss whether or not that’s a good idea to have a class of 200 properties. But you know what? Life happens, and now you start changing those. Well, now we have two copies of each of the properties that have been changed in memory, and if you’ve thousands of these in memory, then we can argue whether or not you should have thousands of things in memory, but now, we are adding some memory pressure.

21:02 - So we can argue whether or not you should have 1,000 items in memory, and I would say you shouldn’t. But again, life happens. But now we can possibly be creating memory pressure, and that memory pressure is because we have all this change tracking going on. So I want to point out that we can turn off change tracking when we do a query. So let’s go back to where I am getting a simple query. I’m doing a file, which we’ll talk about probably in the next episode. But let’s do this a little differently.

21:45 - We’ll say var person2 equals my instance of the DbContext, my DbSet which is called person, and I’m going to say where, X Lambda X., and this is just a link. BusinessEntity ID equals five and then I’m going to say as no tracking. Then I can actually also do first or defaults, I’m not going to do it, it doesn’t matter for this demo. What this query here does, if I would make it in comparison and not an assignment, this then says, get this thing back, but don’t add it to the change tracker. We’re not going to update it. So it’s in your DbSet, but the change tracker says, “I don’t care what you do.

22:46 - I’m never been to report this back to the DbContext, you’ve changed it.” >> Okay. So that be something you might do if you’re pulling down records to display in a list or something, or if it’s just read-only data? >> If you have a really high volume website, let’s say it’s an MVC style application. What I see people doing is that on all of the GETs, they will pull the data back as no tracking because you can’t update from a GET, you’re just playing it on the page. Then, on the post though actually, and on all the GETs, they’re only displaying the date, I should do an update. So in the GET methods, HTTP GET version of an action method, they’ll use as no tracking to pull back with no tracking information.

23:40 - Then on the post where they’re actually updating the data, they’ll use Entity Framework Core with the changed tracker to get those updates. Now we’re not talking about a huge amount of performance differences. But if your Stack Overflow, for example, when you’re getting thousands of requests per hour, maybe per minute, then it matters. If this is your internal line of business app where you’re processing legal cases with your 50 person law firm, it’s probably not going to make that much of a difference. >> Okay. >> There’s one other thing I want to talk about before we close up this episode in that our query types or items that do not have a primary key.

24:27 - So in prior versions of EF Core, we had a DbQuery type. What we have now is a specialized DbSet where we tell it and it doesn’t have a primary key and we don’t have to call as no tracking on it, it automatically knows not to add, it’s a change tracker. This is useful for views, restore procedures, or for, as we’ll see in a later episode, doing a from sequel code to pull back data where the link may be difficult to write, but you want to do these joints. >> All right. So I think is a good place to stop on this episode. >> Absolutely. >> In the next episode, we will start querying the data. Yeah. >> Yeah.

So next episode we’ll 25:17 - talk about querying and we’ll talk about projections, about how to do joins filtering, paging, sorting, all that fun and excitement. >> Cool. So we’ll see you next time on Visual Studio Toolbox. [MUSIC] .