Okay, so we're getting our orders back and we've got the ability to create an order.
And now we'll take a look at shaping the order data back.
It's not too bad, but it could do with some improvements.
Obviously we've got an issue with the order items here.
We've got an issue with the order status.
And perhaps I would like things to be organized in here slightly better, especially if I do take a
look at the one with the order items.
We've got a lot of nesting going on inside here.
That's not particularly helpful when it comes to using this data in our client.
So we will go back and we'll shape our data from our order controller.
Now we did something like this before with our basket extensions.
And we created a method to effectively map the properties from one thing to another thing.
And we'll do similar for our order as well.
So that means creating dtos something to shape the data into.
And I'm going to create a new file which is going to be a class, and I'm going to call it order DTO.
And I'm also going to create another class inside the DTO folder.
And this is going to be for our order item DTO.
And let's go and grab the order Entity code, which might be helpful.
And save us a bit of typing.
And I'll copy all of this into my clipboard and paste it into the order DTO.
And let's remove some of the tabs from the top here.
And I've lost the order DTO.
So let's open that again.
And let's paste in the properties from our order inside here.
And we'll just see what adjustments we might want to make to this.
I'm going to keep the shipping address as shipping address.
That's okay.
The order dates I'm going to remove the equals date time.
Now because this is a DTO the order items.
That's going to be a list.
Of order item DTO.
The subtotal delivery fee discount that can stay the same and we won't send back the payment intent
ID we don't need that on the client.
The order status will return as a string and we'll remove its initial value.
And the payment summary will just keep the same as well inside the order item DTO.
Let's just add these in manually.
We'll have a proper it's an int that's going to be for the product ID we'll have a prop that's a string
for the name.
We'll have a prop that's a string for the picture URL.
We'll have a prop that's a long for the price.
And we'll have a prop that's an int for the quantity.
And let's just make this required and we'll make the picture URL required as well.
And I've got an issue in my order DTO.
What did I do here?
And looks like I've lost some using statements.
So I'll just add the order aggregate in there.
And the order items I'll just make this in fact because it's a list I'll just make this square brackets
to initialize that.
And for our order status I'll set this to be required as well.
Okay.
So if we refer back to what we did in our basket extensions, just to give us an idea of where we're
going with this, we need to write this kind of code to shape effectively our order into an order DTO.
Now, this code is a little bit tedious to write, and there is tools out there to help us with that
called Automapper.
But I'm going to stick with doing this using an extension method.
And we will take a look at Automapper a bit later when it comes to the Crud operations, because it's
more helpful then.
But some developers don't like Automapper, and I'm going to keep the majority of examples to not using
Automapper.
And inside the extensions, let's create another extension class and I'm going to call this well let's
select class and I'll say order extensions.
And inside here once again we'll make this a static class.
And I want to approach this slightly differently this one.
And let's close the others down.
Getting quite busy at the top there.
I'm just going to go back to the orders controller and take a look at what we're doing inside here.
And what we are doing is when we let's pick the get requests and when we return these.
And the reason we wasn't getting the order items is I forgot to include the include.
So I'll just add that in here temporarily.
And what we're doing with these include statements.
This is referred to as eager loading.
So instead of using eager loading we'll use projection.
And I'll demonstrate an example of using projection here.
So instead of including everything from the order items, we only select what we need to from the database.
So let's take a look at how we can configure this.
And inside here we'll have two versions of this.
We'll have a public static.
And this is going to be an I o variable of type order DTO that we are going to return from this.
And this is the one that we're going to use with our query.
And we'll use or we'll give it a name of project two DTO.
And we'll say this I queryable of type order as what we're passing into this we get from API entities
order aggregate and we'll call it query inside here we can return and we'll use query.
And then we'll use select so that we can make use of projection.
And we'll use order as the argument and say New order DTO.
And then inside here we'll open curly brackets.
And then we'll just start mapping the different properties.
So the ID is going to be the order ID the buyer email is going to be the order via email.
The order dates is going to be the order dot order dates.
The shipping address is going to be the order dot shipping address.
The payment summary is going to be the order dot payment summary.
The delivery fee will be the order dot delivery fee.
The subtotal is going to be the order dot subtotal.
The order status is going to be the order dot order status.
And then we'll use the two string method on this so that we get the string value of the enum returned
the total, and I do not have the total currently in my order DTO.
So let's open up the order DTO because I wish to return that as well with this.
So after the discount, I'm just going to have a prop of long for the total and back to our extensions
and then specify the total is going to be the order dot get total to calculate that amount.
And for the order items we'll say order dot order items.
But we wish list to be projected into a DTO as well.
So I'll use select and we'll say item add the arrow and new order item DTO and then open curly brackets.
And we'll have our product ID is going to be the item dot item ordered dot product ID the name will
be the item dot item ordered dot name.
The picture URL will be the item ordered item ordered dot picture URL.
Almost there.
The price is going to be the item dot price, and the quantity is going to be the item dot quantity.
And then we can output this to a list for our order items.
And then close this off with a semicolon.
So that's our mapping code from the order to the order DTO.
And we can use this one in our orders controller.
Instead of using the eager loading here we can specify that we wish.
Instead of this include.
We can specify that we wish to use the context orders.
And then we can use our project to DTO method.
And we're getting an error here because we're not returning a list of orders.
Now we're projecting this Into and list of order dtos.
So we'll just change the type at the top here.
And then that's going to cover the getting of an order.
And we'll just do the same with the get order details as well.
So instead of include there we'll use our new project to DTO and then just do the same and say that
we're returning an order DTO here.
If we go and test our progress on this and looks like I need to restart the API.
So I'm just going to say yes to this and head over to postman and just take a look at the difference
between what we had before and what we get now that we're using projection.
So I'll click send and I get a tracking query is attempting to project an owned entity without a corresponding
owner in its results.
But owned entities cannot be tracked without their owner.
Either include the owner entity in the result, or make the query non tracking using as no tracking.
So when we go and get things from Entity Framework then.
By default it tracks them in memory.
So if we do make changes to them, then when we call the save changes async method, that tracked entity
is then saved into our database because we're projecting this into a DTO.
The properties that we're projecting to don't have a corresponding owner.
So to get around this, what we will do is simply add no tracking for our Get queries when we use the
project to DTO.
So we'll head back to the orders extension, and we'll just append onto list just below the two list.
We'll just say as no tracking.
And that should satisfy Entity Framework.
Let's just take a look at the terminal.
It tells me Hot Reload has succeeded.
Let's give it a chance and I'll click send again.
And this time we get what we're looking for.
So now we should have our data shaped a bit more cleanly and how we want it.
We can see the order items is now no longer nested as deeply, and we can see the order status is pending
and we've got our total inside there as well.
If I check the get order details and do the same thing, then we should have the same.
We should have our well, it's going to be effectively the same because we've only got one order.
Great.
But we've also got our create order.
And if we take a look at what we got back from there, this is not shaped as a DTO.
So we also wish to shape this as a DTO.
But we're not going to project this.
So we need another extension method inside our order extensions just to convert what we have to a DTO.
So below this methods, the project to DTO will have public static, and this one is just going to return
an order DTO and we'll just call it to DTO and we'll pass in this order and call it order.
And we need to return a new DTO with effectively exactly the same code.
So I'm just going to copy what we have in here up and to just before the as no tracking into my clipboard
and I will return and then paste in what I have and just make any small adjustments we need to.
I don't need this extra parentheses at the end there, and just need to close this off with a semicolon.
So that's our code for just making an order and shaping that into an order DTO.
Otherwise, the code is exactly the same as what we used inside the projection one.
So inside our orders controller again let's take a look at our create order.
And everything can stay the same inside here.
But where we're returning our order, let's just use our order to DTO method.
And now when we create a new order, we should get it shaped just like our get request.
And let's give that a test.
So we're going to need a new basket as currently if I get a basket because we've created an order using
this basket, what I should get is 204 no content.
So we need a new basket.
So I'm just going to add an item to the basket which will create us a basket.
So I'll click send on this one.
We've got our basket but it doesn't have a payment intent ID.
So we're going to need to create that payment intent for this one.
So I'll click Create Payment Intent and I'll click send.
And this goes off to stripe.
And it populates the client secrets and the payment intent ID.
And then we can go ahead and create our order.
So I'll go ahead and do that now and click send.
And we get our order back with the ID of two.
And we've got our response shaped just how we want it.
So great.
So that's as far as we can go for the API side of things for the time being.
Next we'll move on to the client side and deal with the orders in there.