|
One of the most common operations you can perform on
records consists of joining them based on a condition. Joining records
consists of creating a list of records from more than one set of records. In
order to do this, you specify the lists, you specify a value they have in
common, and you define the joining relationship. To create a join, you must
use some lists, like those we have created so far.
|
The primary formula to create a join is:
join JoinName
in ChildList
on Condition
The join condition is created before the
select statement. You start with the join
keyword followed by a name. The name can be used later or you can ignore
it. Here is an example of starting a join:
var persons = from staffMembers
in employees
join std . . .
select staffMembers;
var vdos = from videos
in lstDirectors
join vdo . . .
select Something;
The join operation is followed by the
in keyword. The ChildList specifies the list
created from the child class. This can be the list created by the previous
in statement. Here is an example:
var persons = from staffMembers
in employees
join std in employees . . .
select staffMembers;
var vdos = from videos
in lstDirectors
join vdo in lstVideos . . .
select Something;
Of course, you can write the in
statement on its own line. The Condition holds a logical expression
that specifies the relationship by which the records will be joined.
To support joins, the C# language provides a
context-sensitive keyword named equals. Therefore, to
create a join in LINQ, the values used to establish the link in the
join statement should use the object of the from
statement and that of the join clause. Having those
values, you can access the joining property from each object and apply the
equals operator on them. The formula would be:
ChildField equals ParentField
When you create a condition, the compiler (or rather
the LINQ interpreter) would check each record of the child list that has a
value for the corresponding property of the parent list.
A cross join is a set that includes all records from
two lists as follows: the first record from the first list is associated
to each record from the second list. Then the second record from the first
list is associated to each record from the second list, and so on. There
are two ways you create a cross join in LINQ.
For a cross join, you can use one type of collection
(such as a list of numbers, a list for videos, etc) and another type of
list (such as a list of names, a list of music albums, etc). You can then
create a common list that includes items from each list. To create a cross
join, you can use a combination of from...in...
statement for each sub-list. Here is an example:
var vdos = from videos in lstVideos
from albums in lstMusic
select . . .;
Then, in the select statement,
provide a way to retrieve the members from each list. This can be done by
using the new operator and creating a list of fields
inside the curly brackets. This can be done as follows:
using System;
using System.Linq;
using System.Drawing;
using System.Windows.Forms;
using System.Collections.Generic;
public class Exercise : Form
{
private Button btnShow;
private ColumnHeader colVideoTitle;
private ColumnHeader colDirector;
private ColumnHeader colRating;
private ColumnHeader colYearReleased;
private ColumnHeader colAlbumTitle;
private ColumnHeader colMusician;
ListView lvwCollection;
public Exercise()
{
InitializeComponent();
}
void InitializeComponent()
{
btnShow = new Button();
btnShow.Location = new System.Drawing.Point(12, 12);
btnShow.Width = 75;
btnShow.Text = "Show";
btnShow.Click += new System.EventHandler(this.btnShow_Click);
lvwCollection = new ListView();
lvwCollection.Anchor = AnchorStyles.Left | AnchorStyles.Top |
AnchorStyles.Right | AnchorStyles.Bottom;
lvwCollection.FullRowSelect = true;
lvwCollection.GridLines = true;
lvwCollection.Location = new Point(12, 40);
lvwCollection.Size = new System.Drawing.Size(580, 192);
lvwCollection.View = View.Details;
colVideoTitle = new ColumnHeader();
colVideoTitle.Text = "Video Title";
colVideoTitle.Width = 160;
lvwCollection.Columns.Add(colVideoTitle);
colDirector = new ColumnHeader();
colDirector.Text = "Director";
colDirector.Width = 130;
lvwCollection.Columns.Add(colDirector);
colRating = new ColumnHeader();
colRating.Text = "Rating";
colRating.Width = 50;
colRating.TextAlign = HorizontalAlignment.Center;
lvwCollection.Columns.Add(colRating);
colYearReleased = new ColumnHeader();
colYearReleased.Text = "Year";
colYearReleased.Width = 40;
colYearReleased.TextAlign = HorizontalAlignment.Right;
lvwCollection.Columns.Add(colYearReleased);
colAlbumTitle = new ColumnHeader();
colAlbumTitle.Text = "Album Title";
colAlbumTitle.Width = 110;
lvwCollection.Columns.Add(colAlbumTitle);
colMusician = new ColumnHeader();
colMusician.Text = "Musician";
colMusician.Width = 80;
lvwCollection.Columns.Add(colMusician);
Size = new System.Drawing.Size(610, 270);
Controls.Add(this.btnShow);
Controls.Add(this.lvwCollection);
Text = "Entertainment";
}
private void btnShow_Click(object sender, EventArgs e)
{
List<Video> lstVideos = new List<Video>();
lstVideos.Add(new Video("Two for the Money", "D.J. Caruso", "R", "2008"));
lstVideos.Add(new Video("Her Alibi", "Bruce Beresford", "PG-13", "1998"));
lstVideos.Add(new Video("Distinguished Gentleman (The)", "Jonathan Lynn", "R", ""));
lstVideos.Add(new Video("Memoirs of a Geisha", "Rob Marshall", "PG-13", "2006"));
lstVideos.Add(new Video("Wall Street", "Oliver Stone", "R", "2000"));
lstVideos.Add(new Video("Sneakers", "Phil Alden Robinson", "PG-13", "1992"));
List<Music> lstAlbums = new List<Music>();
lstAlbums.Add(new Music("WordSound&Power", "Christafari"));
lstAlbums.Add(new Music("Tribute", "Yanni"));
lstAlbums.Add(new Music("Mutuashi", "Tshala Muana"));
var vdos = from videos in lstVideos
from albums in lstAlbums
select new
{
videos.VideoTitle,
videos.Director,
videos.Rating,
videos.YearReleased,
albums.AlbumTitle,
albums.Artist
};
foreach (var item in vdos)
{
ListViewItem lviCollection = new ListViewItem(item.VideoTitle);
lviCollection.SubItems.Add(item.Director);
lviCollection.SubItems.Add(item.Rating);
lviCollection.SubItems.Add(item.YearReleased);
lviCollection.SubItems.Add(item.AlbumTitle);
lviCollection.SubItems.Add(item.Artist);
lvwCollection.Items.Add(lviCollection);
}
}
[STAThread]
public static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}
public class Video
{
public string VideoTitle { get; set; }
public string Director { get; set; }
public string Rating { get; set; }
public string YearReleased { get; set; }
public Video(string title = "",
string dir = "",
string ratings = "",
string year = "")
{
VideoTitle = title;
Director = dir;
Rating = ratings;
YearReleased = year;
}
}
public class Music
{
public string AlbumTitle { get; set; }
public string Artist { get; set; }
public Music(string ttl, string musician)
{
AlbumTitle = ttl;
Artist = musician;
}
}
This would produce:
Notice that each record from one list is associated to
each record of the other list. To put a restriction in the list of values,
you can add a where condition. Here is an example:
var vdos = from videos in lstVideos
from albums in lstAlbums
where videos.Rating.Equals("R")
select new { videos.VideoTitle, videos.Director,
videos.Rating, videos.YearReleased,
albums.AlbumTitle, albums.Artist };
This would produce:
In the same way, you can create a where
statement for each from list. Here is an example:
var vdos = from videos
in lstVideos
from albums
in lstAlbums
where videos.Rating.Equals("R")
where albums.Artist.Equals("Yanni")
select new
{
videos.VideoTitle,
videos.Director,
videos.Rating,
videos.YearReleased,
albums.AlbumTitle,
albums.Artist
};
This can also be written as follows:
var vdos = from videos
in lstVideos
where videos.Rating.Equals("R")
from albums
in lstAlbums
where albums.Artist.Equals("Yanni")
select new
{
videos.VideoTitle,
videos.Director,
videos.Rating,
videos.YearReleased,
albums.AlbumTitle,
albums.Artist
};
This would produce:
The second technique of creating a cross join involves
two lists that have a relationship. You start with a class that can be
used as the basis of a list. Here is an example of a class that would be
used to create a list of movie (or video) directors:
public class Director
{
public string DirectorID { get; set; }
public string Name { get; set; }
}
Before creating the join, you should (must) have a
member from each class so that these two members will be used to join the
lists. These members should hold unique values. In the above class, that
would be the role of the DirectorID property, where we would make sure
that each record has a unique DirectorID value.
When creating the other class, you should (must)
create a property (or field) that represents the unique-value provider of
the first class. In our example, when creating a class that will be used
to create a list of videos, we must create a property (or field) that
represents the DirectorID of the first class. The class can be created as
follows:
public class Video
{
public string ShelfNumber { get; set; }
public string VideoTitle { get; set; }
public string DirectorID { get; set; }
public string Length { get; set; }
public string Rating { get; set; }
public string YearReleased { get; set; }
public Video(string number = "",
string title = "",
string dir = "",
string len = "",
string ratings = "",
string year = "")
{
ShelfNumber = number;
Title = title;
DirectorID = dir;
Length = len;
Rating = ratings;
YearReleased = year;
}
}
To create a cross join, apply the square brackets to
the from and the join statements to
indicate the index by which the records would be established (you can use
the square brackets whether the lists were created as arrays or using the
List<> class). Here is an example of creating a cross
join (all properties were created as strings for illustration; this was
made so that, when they don't have a value, they would be empty; if they
used the int data type, their values would be set to 0):
using System;
using System.Linq;
using System.Drawing;
using System.Windows.Forms;
using System.Collections.Generic;
public class Exercise : Form
{
private Button btnShow;
private ColumnHeader colShelfNumber;
private ColumnHeader colVideoTitle;
private ColumnHeader colDirectorID;
private ColumnHeader colLength;
private ColumnHeader colRating;
private ColumnHeader colYearReleased;
ListView lvwCollection;
public Exercise()
{
InitializeComponent();
}
void InitializeComponent()
{
btnShow = new Button();
btnShow.Location = new System.Drawing.Point(12, 8);
btnShow.Width = 75;
btnShow.Text = "Show";
btnShow.Click += new System.EventHandler(this.btnShow_Click);
lvwCollection = new ListView();
lvwCollection.Anchor = AnchorStyles.Left | AnchorStyles.Top |
AnchorStyles.Right | AnchorStyles.Bottom;
lvwCollection.FullRowSelect = true;
lvwCollection.GridLines = true;
lvwCollection.Location = new Point(12, 40);
lvwCollection.Size = new System.Drawing.Size(520, 192);
lvwCollection.View = View.Details;
colShelfNumber = new ColumnHeader();
colShelfNumber.Text = "Shelf #";
lvwCollection.Columns.Add(colShelfNumber);
colVideoTitle = new ColumnHeader();
colVideoTitle.Text = "Video Title";
colVideoTitle.Width = 160;
lvwCollection.Columns.Add(colVideoTitle);
colDirectorID = new ColumnHeader();
colDirectorID.Text = "Director";
colDirectorID.TextAlign = HorizontalAlignment.Center;
colDirectorID.Width = 100;
lvwCollection.Columns.Add(colDirectorID);
colLength = new ColumnHeader();
colLength.Text = "Length";
colLength.Width = 80;
lvwCollection.Columns.Add(colLength);
colRating = new ColumnHeader();
colRating.Text = "Rating";
colRating.Width = 50;
colRating.TextAlign = HorizontalAlignment.Center;
lvwCollection.Columns.Add(colRating);
colYearReleased = new ColumnHeader();
colYearReleased.Text = "(c) Year";
colYearReleased.TextAlign = HorizontalAlignment.Center;
lvwCollection.Columns.Add(colYearReleased);
Size = new System.Drawing.Size(550, 270);
Controls.Add(this.btnShow);
Controls.Add(this.lvwCollection);
Text = "Entertainment";
}
private void btnShow_Click(object sender, EventArgs e)
{
Director[] lstDirectors = new Director[3];
lstDirectors[0] = new Director();
lstDirectors[0].DirectorID = 1;
lstDirectors[0].Name = "Rob Marshall";
lstDirectors[1] = new Director(2, "Oliver Stone");
lstDirectors[2] = new Director(3, "Jonathan Lynn");
Video[] lstVideos = new Video[]
{
new Video("927940", "Natural Born Killers", 2, "118 minutes", "R", "1994"),
new Video("", "Platoon", 2, "120 minutes", "", "1986"),
new Video("279472", "Outfoxed"),
new Video("725917", "Distinguished Gentleman (The)", 3, "112 minutes", "R"),
new Video("", "Memoirs of a Geisha", 1, "", "PG-13", "2006"),
new Video("291705", "My Cousin Vinny", 3, "120 minutes", "", "1992"),
new Video("248115", "", 0, "", "R"),
new Video("", "Wall Street", 2, "", "R", "2000")
};
var vdos = from videos
in lstDirectors
join vdo in lstVideos on lstDirectors[1].DirectorID equals lstVideos[1].DirectorID
select new { Shelf = vdo.ShelfNumber,
Title = vdo.VideoTitle,
Manager = videos.Name,
Length = vdo.Length,
Classification = vdo.Rating,
Copyright = vdo.YearReleased };
foreach (var item in vdos)
{
ListViewItem lviCollection = new ListViewItem(item.Shelf);
lviCollection.SubItems.Add(item.Title);
lviCollection.SubItems.Add(item.Manager.ToString());
lviCollection.SubItems.Add(item.Length);
lviCollection.SubItems.Add(item.Classification);
lviCollection.SubItems.Add(item.Copyright);
lvwCollection.Items.Add(lviCollection);
}
}
[STAThread]
public static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}
public class Director
{
public int DirectorID { get; set; }
public string Name { get; set; }
public Director(int dirID = 0, string dir = "")
{
DirectorID = dirID;
Name = dir;
}
}
public class Video
{
public string ShelfNumber { get; set; }
public string VideoTitle { get; set; }
public int DirectorID { get; set; }
public string Length { get; set; }
public string Rating { get; set; }
public string YearReleased { get; set; }
public Video(string number = "",
string title = "",
int dir = 0,
string len = "",
string rate = "",
string year = "")
{
ShelfNumber = number;
VideoTitle = title;
DirectorID = dir;
Length = len;
Rating = rate;
YearReleased = year;
}
}
This would produce:
Notice that each record of the parent class (Director)
is associted to each record of the child class (Video).