|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionMicrosoft is working very hard on Visual Studio codename "Orcas", and recently released LINQ CTP (May) and ADO.NET vNext. This article is based on the LINQ May 2006 CTP. PrerequisitesIn order to run the samples and follow the article, you must have:
Start new projectAfter you have installed LINQ, you will have LINQ related templates in VS2005. So create a new project as follows:
Well… now we have a new Windows Forms application with an empty form. Let's generate the code for the database objects. Using Code Generation to Create the Object Model
Now, we have generated entities and they are ready to be queried. List entities using LINQ
Execute the project to confirm results. (I added a movie so the table won't be empty). So far so good. Microsoft confirmed that one-to-one and one-to-many relations are supported in the SQL Metal tool (the tool we used to generate code in MovieCollection.cs). What if we are anxious and we would like to support it? Add many-to-many relationsIn this database, we have two entity tables (Movie and Category) and a junction table, MovieCategory, for many-to-many support.
We have to write some code to support it, but it's worth the effort. First we need access to the DataContext instanceWe have to get all objects from one instance. In this way, data consistency is guaranteed. (For more info, see DLinq Hands on Lab for C#/VB.NET form LINQ CTP). In the Program.cs file, write: private static MovieCollection dataContext = null;
internal static MovieCollection DataContext
{
get
{
if (null == dataContext)
{
dataContext =
new MovieCollection(@"Data Source=.\SQLEXPRESS;" +
@"Database = MovieCollection;" +
@"Integrated Security=True;");
}
return dataContext;
}
}
We will use this Singleton implementation to access the database only from one point. To ensure this, we have to change the private void Form1_Load(object sender, EventArgs e)
{
movieBindingSource.DataSource = Program.DataContext.Movies;
}
Extend the Movie classThe next thing to do is to extend the public partial class Movie
{
protected EntitySet<Category> categories;
/// <summary>
/// Return assigned categories to current movie
/// </summary>
public EntitySet<Category> Categories
{
get
{
categories = new EntitySet<Category>(onAddCategory, onRemoveCategory);
var cats = from c in Program.DataContext.Categories
join mc in Program.DataContext.MovieCategories
on c.CategoryID equals mc.CategoryID
where mc.MovieID == this.MovieID
select c;
//add to result
foreach (var c in cats)
categories.Add(c);
return categories;
}
}
protected void onAddCategory(Category arg)
{
//add entry to MovieCategories table
MovieCategory mc = new MovieCategory();
mc.MovieID = this.MovieID;
mc.CategoryID = arg.CategoryID;
Program.DataContext.MovieCategories.Add(mc);
}
protected void onRemoveCategory(Category arg)
{
}
}
Believe it or not, this is all we need to extract all the categories to a certain movie. What we've just did?Let's explain the code step by step. We created a new property for the categories = new EntitySet Category (onAddCategory, onRemoveCategory);
The next statement performs a LINQ query against the objects. Unfortunately, we must have access to the var cats = from c in Program.DataContext.Categories
join mc in Program.DataContext.MovieCategories
on c.CategoryID equals mc.CategoryID
where mc.MovieID == this.MovieID
select c;
This query is translated to SQL as: SELECT [t0].[CategoryID], [t0].[CategoryName]
FROM [Category] AS [t0], [MovieCategory] AS [t1]
WHERE ([t1].[MovieID] = 1) AND ([t0].[CategoryID] = [t1].[CategoryID])
The next two lines are easy: fill the private collection and return it as the result. //add to result
foreach (var c in cats)
categories.Add(c);
return categories;
The delegate Are you sure this is all?Let's create another
History
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||