>> On today's Visual studio Toolbox,
Phil explores Entity Framework Cores change tracking events.
[MUSIC]
>> Hi, welcome to Visual Studio Toolbox.
I'm your host, Robert Green,
and with me today is Phil Japikse. Hello, Phil.
>> Hey, Robert.
>> Well, into our entity framework
core series nearing the end of it.
>> Look, who would guess?
>> Today, we're going to talk about change tracking events.
I'm interested in this one because,
I didn't necessarily know what that
was when you suggested we talk about it.
>> Yeah, so one of the things that was nice in
EF6 that really didn't make it forward,
I'm into EF Core,
it's a non-materialized event,
and the unmaterialized event would fire when
an object was reconstituted from the database into a class.
Now why that matters was,
for example for MVVM,
and actually the next show we're going to talk
about is how they fixed the problem in MVVM,
the right way for MVVM in EF Cores, we don't need that anymore.
But to change tracking events to two things now,
it will raise an event when something where
it's state has changed, its entity states.
So maybe it's gone from added to not
modified or not modified to edited,
and it'll also fire an event when
something is added into the ChangeTracker.
>> Okay.
>> Now why this matters is if you want to set up some logging,
there is a couple of ways you can do change logging.
You can certainly do database triggers,
and a lot of people do that,
and we could argue for where I have a whole bunch
of shows and get different people
on to say whether they love or hate triggers,
there's no middle ground with triggers.
But if you don't want to use triggers,
here's a way in code that you can accomplish the same thing,
and we've done this for a lot of our financial customers.
So we'll have, for example,
a customer's table and then a customer audits table,
and any time a change is made to
a customer record we automatically
write to the customer audit table.
So they can go back to any point in
time and see this data as it changes.
>> Okay.
>> Does that makes sense?
>> Yeah.
>> Let's look at code. So we've got two events that we can hook
into with an application DbContext or a derived DbContext.
The track changed and the state changed.
So the track change is fired when something
goes from not being tracked to being tracked.
If it comes in from a link statement or some EF query,
whether that's from SQL,
interpolated from SQL raw regular link,
then it's going to come in with the from
query property set to true.
Let me remove the breakpoint for
now so you can see my highlighting,
that'll be set to true,
so then we can say it came from the database.
Otherwise it's going to indicate that it came from code.
In other words, I said,
blog b equals new blog context.blogs.add b.
I haven't
called SaveChanges by added into the ChangeTracker.
>> Geez, is that a lot?
That would seem like you already know where it came
from in your code because you just
wrote the code to get it in there.
>> So I don't use it a lot.
Sometimes there's some edge cases where I
used it and it was more of working with the context holistically.
Like if I've added a blog,
but I've also pulled four blogs back.
So now I have these five blogs in there and I've edited two
of my deleted another one and I go to call save,
and one was from source that I know it's brand new.
The other one was from queries and I know is changed.
>> Okay.
>> No, I don't use it a ton and I'm blanking right now.
It was two different edge cases where we used it, but it's there.
>> Yeah.
>> So the state changed is a little more convoluted.
This is good at
the properties on E. So there's
really just the old state and the new state.
>> Okay.
>> So I'm looking at the old state
and the new state to determine the action.
I think the easiest way to show this is to step through some code.
So let's do this. Let's just run this.
I want to create a new blog.
Want to add it into the ChangeTracker.
Well, I'm adding it into the DB set,
which was an added to a ChangeTracker.
Then I'm going to call
SaveChanges and let's just watch how these things trigger.
>> Okay.
>> It's rebuilding, a database right now.
I won't bother showing
the Command Window because it just as a Command Window.
>> So the old state whose before
changes made new state is after a change
was made in every entity has a pair of those in the ChangeTracker.
>> So I've just added the blog.
>> Yeah.
>> It was not from a query, it was from a code.
So I'm going to output that
the entry Schema's blog was added from code.
>> Okay.
>> All right. So let me run.
So now, we have also triggered the state changed.
If we look at states.
>> Now, again, this is after the add or before the SaveChanges?
>> Correct. Here we do.
We added to the DB sets,
but we haven't called SaveChanges.
We have then output that, the blog was added from code.
>> Right.
>> All right. Let me do a continue.
>> To attract fires before changed.
>> You'll notice that change didn't fire at all.
>> Okay.
>> Because this state never changed?
>> Got it. Okay.
>> All right. So now, I've added the blog.
So maybe this is the part of where the fuzzy is coming.
The change tracker is tracking states.
Then after the event,
it's no longer the same state as the ChangeTracker that fired it,
it's the after effect because it's
going to fire after I call SaveChanges.
So I've just called SaveChanges.
>> Date doesn't change when you add something to the DbContext?
>> It comes in as added,
it doesn't come in as unmodified.
>> Okay.
>> So it actually hasn't changed, it's been assigned.
>> Okay. Got it.
So the initial setting is not a change,
it's just an initialization.
>> Yeah.
>> Good to know.
>> All right, so my entry is a blog.
>> Yeah. What's the old state, what's the new state?
Show us those right now.
>> Schematics blog was added old state,
before the state was changed to unchanged.
>> Okay, so when you added it,
it started out as added and then you
saved it and it is now unchanged.
Got it.
>> We didn't do any editing, so we could modify it.
We didn't try and delete it.
>> Got it.
>> This is not all of the code of course,
because you got to pay me for that.
>> I'm paying you for this much either?
>> Yeah, pay me for this either.
Once I say this,
you're going to get all the code, are you going to hire me.
So I'm checking the new state.
So the new state is unchanged, which means it has
been persistent, it's unchanged.
Now, I'm going to get the old state.
So there's the action, it was added.
So in my logging table,
I can then grab the values of
the blog record as it is now and write it and say it was added.
>> Got it.
>> You're going to be logging the data after it's been changed.
>> Okay.
> It doesn't make sense to log it before it's been changed,
because if you don't have a blog,
what are you going to log, right?
>> Right.
>> But I could then go and call code to say okay,
save to the logging table,
the blog status and then now I'm going to
have a running history of
all of the changes and I can put in there as one of
the fields in the audit table and this is what
we do is what the action was,
was it added, was it deleted, was it edited?
Then we dump out the entire record and then you can use
SQL Server Reporting Services
and all BI tools to do analysis of it.
>> Okay.
>> So this is something that we use fairly often.
Let me close my console window.
There's something else that was added in,
that has the same name as EF6 code
and the name does work because it truly is an interceptor,
but it doesn't work the same way EF6 interceptors worked.
So in EF Core,
I can do a command interceptor,
a connection interceptor, or a transaction interceptor.
>> What is an interceptor?
>> An interceptor is going between your code and EF Core.
It's listening, it's going to intercept in this example.
I'm starting a transaction,
it's going to intercept that call,
you can do stuff with it,
and then it'll let it continue through.
So if you think of the old commerce pipeline analogy,
if you've worked with commerce server or any of those.
So I've got the pipeline, I've got this transaction that started.
It starts in the EF Core,
goes to the database, comes back.
So as interceptor, I misspoke I said
between your code and EF Core.
In this case it's between EF Core and the database provider.
It's going to start this transaction,
I intercept, I can then do things to it.
So I have access to the event data,
the connection ID, whether or not it ain't saying what
the isolation level is some of these are get only,
some of them are get set the transaction ID,
I do have access to the context so I can actually look at
what's in there in the ChangeTracker.
You have full access to stuff.
I'm going to be completely transparent in that I haven't
found good real world uses for these yet.
The reason that I say I haven't really found
a good use for it yet,
is I've got command creating failed.
I guess there's something,
the command and the executing failed that were logged at,
but I have logging all over my apps anyway.
What I don't have access to that I wish I did,
and this is me just going back to the EF6 days,
is something that says give me the objects as
they're coming back before they're
fully realized and available to my app,
I might want to do something with it.
This is me taking the end notify property change issue that we had
with WPF and EF6 that was resolved by doing an interceptor.
But there's a bunch of them, the way you plug them in.
Again, hopefully readers are putting comments.
If you're using these, we're using
them because that would be great.
I just haven't found the use
yet and maybe I haven't looked hard enough,
but again this goes back to
the dynamic configuration capabilities within EF Core.
So I'm saying use SQL Server and by
the way I want to add these interceptors.
>> Okay.
>> Those are interceptors.
>> Cool.
>> It's a lot of power to look at.
I don't have a real business case for it yet,
but hopefully somebody would chime in on
the comments and fill us both in.
>> Awesome. All right, good stuff.
Hope you guys enjoyed that and we'll see
you next time on Visual Studio Toolbox.
>> See you soon. Thanks.
[MUSIC]