JeremyBytes - Lambdas & LINQ in C# - Bonus: Deciphering the Join Method

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
this is Jeremy Clarke of Jeremy bytes calm and we're going to continue our discussion of lambda expressions and link and c-sharp in this episode we're going to decipher the join method why does this come up well back in episode 2 we demystified the method signatures that we have for link so we looked at where and we saw how it's an extension method on ienumerable and it also takes a delegate a func of t source bool and as we saw it's pretty easy to use this method once we understand the different parts we also looked at the order by method which has a similar signature so it is also an extension method on ienumerable and it also takes a delegate and this time instead of being a func of t source bool this is a func of t source t key something that we can use to establish some kind of ordering and in those examples we became very comfortable with this and we saw that it's not very hard once we understand the pieces but the last few times I've shown this I've gotten the same question how do we use the join method now why does this come up well because this is the method signature for join and who can figure out how to use this well you know what we're going to figure out how to use this and what we'll see is that all of the pieces and the join method are exactly the same pieces we've already dealt with they're just put together a little bit differently now there are two different ways that we can do link we have the query syntax and the fluent syntax so far we've just looked at the fluent syntax where we dot our extension methods together but to help us understand how to use the join method we're actually going to look at it in the query syntax as well so let's head over to the code so here we are in Visual Studio and we'll be looking at a project in the bonus folder you can get this code from github by just following the links in the video notes today we'll be looking at the joins syntax project this is a fairly simple project it's just a console application but we do have two different data sets that we can join together first we have people and if we look at our class we see that this has a single method called get people and this returns an by a numeral of person objects and if we look at the contents of this method we see it just returns a hard-coded collection now the person class itself is pretty simple it has the same four properties we've been looking at previously a first name a last name a start date and a rating but in addition it also has an ID property this is a primary key that we can use to link our data together now in addition to our people class we also have an order's class and we see this has a single method called get orders that returns an enumerable of order and if we look at the contents of this we see it as just a hard-coded collection of order objects now our order class is also pretty simple we see it has an ID a customer ID an order date and the total amount due now the thing we want to pay attention to here is that customer ID is actually a foreign key so this links to the ID property of the person object and this is what we can use to join our two datasets together now in our scenario I want to create a simple reporting object and what this will allow me to do is join our data together and put it in a format that we can use in our application so let's start with the query syntax for this I'm going to create a method and this will be a public static method and this will return an ienumerable of dynamic now the reason I'm using dynamic here is because we're actually going to be using an anonymous type and by using dynamic it will be easy to get the properties out when we show this in our console application now the report that I want to create is order dates by customer so I'll create a method called order dates by customer and then we'll just need to query our data to create this report so to start off with I need my data so I'll start by using the get people method that we have on our people object and we also need our orders so we'll use the get orders method that we have on our orders object so this will get us the data that we can work with so let's go ahead and create our query our output I'm going to call order dates so now we need to create our query first we'll start with our people collection so I'll say from P and people and then we want to do same thing with the orders collection but we want to join our data together so we'll say join o in orders and then we need to tell it how our data relates together so we'll say on PID which is the ID property of our person equals the customer ID from our orders so this is just how we set up that relationship between our people and our orders now the last thing we need to do is tell what data we want to return and for that we normally use the Select statement but select also lets us do a data transformation and that's what we'll do here we don't want to return all of the items from both of our objects instead what we'll do is just return a few of the properties so I'm going to create a new anonymous type and we're just going to pull three properties out so I'm going to take the last name from the person I'm going to take the first name from the person and I'm also going to take the order date off of the order object now what this does is it creates a new type for us that doesn't have a name and this is the primary reason the VAR keyword was created now it's interesting is if we hover over VAR we'll be able to see what comes out of our query so here we'll see that order dates is an ienumerable of T and then if we look more closely we find out that T is tick a now take a is just an internal name that's given to this anonymous type that we created and if we look down below we see that tick a is an anonymous type that has three properties a string called last name a string called first name and a date/time called order date now this was all gathered out of this new anonymous type that we created since last name is a string and first name is a string it figured that out and since order date is a date/time it figures that out as well and it just gave the name of the properties the same name that we're passing in so now that we have this data we can return it so we'll just say return order dates and this is why I'm having this object returned an ienumerable of dynamic you can't directly return an anonymous type because the type itself doesn't have a name that we can work with but if we return dynamic then we can pretty much put any type that we want in here of course that also means we don't get strong types on our other side which we'll see when we start to use this method so let's go ahead and build and make sure everything's okay okay we have a successful build now let's use this method and for this we're going to go to a console application so what we want to do here is get the results out of that method we just created and display them in our console so I'll start by creating a variable to hold the output and we'll call this query order dates since this is using the query syntax and for this we'll just call query order reports dot order dates by customer and then if we look at the type of this VAR it is an ienumerable of T and T is dynamic in this case so it's not an anonymous type it's actually a dynamic object so let's go ahead and output this to the screen and for this we'll just do a for each over the items and we'll do a console dot write line so here's the basics of our write line so I actually want the order date in a particular format and then the first name and the last name and this is where we'll see the downside of using dynamic so if I say item dot notice I get no intellisense at all that's because we're using a dynamic object so I would need to type in order date assuming that that does actually have an order date property on this dynamic object and we'll do the same for the first name and the last name so now let's run our application and see what we get so now we can see all of the dates that orders were placed by particular customers now we don't have any ordering at this point so what we're getting is just based on how our data was put together so even though we do have all of the data it's not very useful at this point so let's go back and add some sorting so for this we'll just go back to our report and we'll just add a new statement so we'll say order by ODOT order date so what this will do is sort based on the date of the order and when we run our application again now we can see that we're sorted by B now the other thing I want to do here is I want to limit the data so I just want to see the items for December to do this well just add some parameters to our method so we'll add a start date and we'll add an end date and then to use these we'll just add a where clause to our query so we'll say we're order date is greater than or equal to start date and order date is less than or equal to end date now before we run our application we'll need to modify the code that's calling this and we can see that we need to add a couple parameters well it happened to have a couple prepared here for us so we can just add start date and end date as parameters and we can see those values are December 1st and December 31st respectively now if we run our application we'll see that we do have a filtered and sorted list so all of our dates are during December 2014 they are sorted by date and we can see that we have about 11 items here so we've seen how to build this simple reporting object with the query syntax now let's go ahead and use the fluent syntax now we know the where and order by won't be any problems at all for us because we've already worked with those methods but the joint method is a little bit harder so let's go ahead and pull up join and help so here's our method signature for join now some of the things that throw people off here is that we have four different generic types t outer t inner t key and t result in addition to that we have five different parameters and three of those are delegates so let's just walk through these objects one at a time if we look at our first parameter we see it's an ienumerable of t outer so this would be one of our collections in this case we'll be dealing with the people object here so wherever we see T outer we can replace that with the type person now our second parameter is also an ienumerable and we'll see this is ienumerable of t inner this will be our orders collection so anywhere we see t inner we can replace that in our mind with order so these first two parameters are just the two collections that we're joining together now to make things more interesting note this keyword on the first parameter that means we can treat this as an extension method on our first parameter again in our case we're using our people collection here so we can say people dot join and then fill in the other parameters and this is really no different than the way we used where and order by in our previous examples now our next two parameters are key selectors so notice we have a func of T outer T key and a func of T inner T key now remember T outer is person and T inner is order so we have a func of person T key and a func of order T key now what is T key well in our order by examples that we saw previously we saw that T key was any type that implemented the I comparable interface now when we're dealing with joins this is a little bit different these need to implement I equate able which means we need to be able to tell whether two objects are equivalent to each other and that makes sense when we think about it because this is how we're setting up that primary key foreign key relationship between our two collections so these two parameters let us specify how our data is joined together now the last parameter is probably the most confusing because we have a func of T outer T inner T result all of our previous funks just had two generic type parameters this one has three now when we're dealing with funk the last generic type parameter is the return type that we're expecting from this delegate all the generic types before that our parameters for our delegate so that means we have a T outer and a T inner and again that's person and order so in this case we want a method that takes a person and an order as a parameter and then returns some kind of result and it turns out this is exactly the same data transformation that we did with our select so let's go ahead and put all of our pieces together so we'll go ahead and create a public static method like we did before this will return an enumerable of dynamic and we'll call this order dates by customer and we're just using the same method name because we're distinguishing these two methods by the static class so this time we're using fluent order reports instead of query order reports and we'll start out with no parameters to get things going now we do still need the people and orders collections so I'll just copy this from our previous method and now we get to start using our link methods with the fluent syntax so we do need an output so we'll save our order dates like we did before and now we need to start linking our data together now as we noted join is an extension method so that means I can go people dot and I do have join as one of my options now when we look at this will see that visual studio has already started doing some of the generic type replacements for us so notice we have ienumerable of person so instead of having t outer it has filled in that type because it knows that we're dealing with the person object now our first parameter is the ienumerable of t inner and again this will be our orders collection since this is what we want to join to and now we start getting to our lambda expressions our next two parameters are the key selectors so again this first one we need a func of person t key so what we're going to say is p which is our person goes to p ID so what we're saying here is that our t key will be this ID property which is an integer and integer does implement the ieee equatable interface now the next parameter that we have is a func of T inner T key now remember our t inner in this case is our order so we can say oh four order goes to ODOT and notice that we have all of our properties here and we can select customer ID so with these two parameters what we're saying is that the ID property of our person is the same as the customer ID on our order so if we go back to our query syntax this would be the equivalent of our on statement where we say on PID equals o dot customer ID now the last parameter we have is our data transformation so notice we have a func of person T inner T result and again our t enter in this case is our order so in this case I need a lambda expression that takes two parameters that means that I do need parentheses around them so for the first one we'll say P for person and for the second one we'll say o for orders and then we'll say goes to and now what we need to do is return the result that we want for this particular object and what are we going to do for that well we're going to do exactly the same thing that we did for the select statement when we were using the query syntax so we'll just create a new anonymous type based on the last name the first name and the order date and if we look at our order dates variable we'll see this looks exactly the same as when we looked at it with the query syntax so this is an enumerable of T where T is tick a an anonymous type and that anonymous type is a string last name a string first name and a date time order date so we see we get exactly the same results from this as we did when we were using the query syntax so let's go ahead and return order dates and then we'll use this in our application so back in our console application what we'll do is we'll go ahead and just create a divider so that we have a division between our outputs so now I'll create a variable called fluent order dates and we'll set this equal to fluent order reports and run that method and then we'll just need two for each over the data like we did before so I'll just copy and paste this code and we'll change query order dates to fluent order dates and our output should be the same as we had above so let's go ahead and run our application to see what we have so we'll see that our query data did scroll off the screen a little bit but if we look at the fluent report we see this is in the same state that we had when we first ran the query data so we do have all of the data but it's not in date order and it's not filtered to show a particular date range so let's go ahead and add those now we already know how to do this because that's what we did in part two of this series so let's start by adding some parameters so we'll have a date time for the start date and we'll have a date time for the end date and now we can use these in a where clause now as we saw previously when we're dealing with the fluent syntax in Lync we generally dot our methods together so since join returns an ienumerable we can keep going and say dot where and then as a parameter we do need to return a predicate now notice here that the type is tick a so it's actually expecting our anonymous type as a parameter and we need to return a true false value and if we need a clue we can see that it tells us exactly what that anonymous type is so let's go ahead and use this I'm going to use our and the reason I'm using R is for result so this will stand for that anonymous type now notice I do get full intellisense on this so since our anonymous type includes a first name a last name and an order date I do get those in my intellisense so we'll say we're order date is greater than or equal to start date and order date is less than or equal to end date now we do also want to add sorting so I'm just going to say dot order by and then we'll say our goes to our dot order date since we want to sort based on the date so what we've just done is implement the same functionality with our fluent syntax as we had with our query syntax now we will need to add some parameters in our application so we'll just say start date and end date we'll just use the same variables that we had above and now if we run our application what we'll see is we have exactly the same result set for our fluent data as we had for our query data so you might say well if we get the same results what's the difference well that's actually a bigger question the primary difference between using the query syntax and the fluent syntax is that the query syntax is much more limited so we do have a number of keywords available to us like from join where order buy and select but there's also a lot of keywords that are not available to us so one thing we looked at last time was the single or default method unfortunately there's no way to do that with the query syntax now we can wrap the results from the query syntax and go ahead and add that single or default to the end if we want and that may make sense in some situations but I've gotten so accustomed to using linked with the lambda expressions that I'm almost always using the fluent syntax these days and that gives me access to all of the methods that we have so let's just review the join syntax one more time so our first parameter is an ienumerable of t outer this is one of our collections in our case we're using a collection of person objects and since this is an extension method we can treat the join method as if it were a method on this first parameter so that's how we can say people dot join now our second parameter is ienumerable of t inner and this is just the other set of data we want to join to so in our case it's our orders object which is an enumerable of order the next two parameters are the key selectors and this is how we relate our datasets to each other so our first delegate says we need to take a person as a parameter and return a T key so we use P for person and our lambda expression and in this case we return the ID property an integer then for the inner key selector we're working with the orders object so our parameter is of type order which we use o in our case for our lambda expression and we return ODOT customer ID which is an integer and it is equal to the ID property of our person object so again these are just two lambda expressions that tell us which properties we use to join our data up and our last parameter gives us a chance to transform the data so this takes a person and an order as a parameter in our case and then we need to return whatever type we want in our case we just create an anonymous type so our lambda expression has two parameters a person and an object which again we're using P and Oh to help our brains remember that and then we're creating a new anonymous type based on the last name the first name and the order date so once we have all of these pieces in place it's not that hard to understand the join method syntax so when we walk up to the syntax of the join declaration it's pretty intimidating but as we've seen it's not that hard once we break the pieces down all we're dealing with is the two sets of data we want to join together setting the key of how we join them and then deciding what kind of data we're returning from this particular method and again if we're comfortable with funk the built-in delegate types and lambda expressions this gets much much easier I love using link methods in my code there's a lot of functionality that's really easy to use once we understand the basics so to download the source code and get links to other articles on this same topic be sure to visit www.kingston.com/support for
Info
Channel: Jeremy Clark
Views: 12,795
Rating: undefined out of 5
Keywords: C# (Programming Language), Language Integrated Query (Programming Language), Anonymous Function, Join, Lambda Expression
Id: tzR2qY6S4yw
Channel Id: undefined
Length: 23min 41sec (1421 seconds)
Published: Fri Apr 24 2015
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.