by
Granville Barnett | 15 September 2007
In the
previous page, you learned how to use LINQ with SQL. In
this page, let's learn how to do more with LINQ using Visual
Studio.
As we have seen, defining entities is simply a case of
mapping an attributed type to a table. Although this process
is very straightforward it can be time-consuming, especially
when you have many tables in your database schema with many
relationships. For this reason the LINQ May CTP includes two
tools, one is a designer hosted in Visual Studio 2005 (DLINQ
objects) and the other is a command line utility,
SqlMetal. We will take a quick look at using the DLINQ
objects item to create a conceptual view of our database
schema.
For Visual Studio 2008 information, click here
to see how the following instructions may be different.
First go into Visual Studio 2005 and create a new LINQ
Console Application, when the solution has been created add
a DLINQObjects item to the solution. At the moment you will
see a blank canvas, drag the tables of your database from
the server explorer window onto the canvas – you have just
created the conceptual view of your database schema.
The main advantage of using the designer is that you are
presented with an entity diagram (as shown in
the image on the previous page) describing your
conceptual model, however you will find the designer becomes
very slow (it’s a CTP remember!) when creating a conceptual
view for a large database schema. For that reason I
recommend you use the SqlMetal command line utility if that
is the case.
Just like we can query in memory collections, we can
also query entities in our conceptual database model. To
interact with our conceptual database model we need to
create a DataContext – this is a very important type in the
System.Data.DLinq namespace. The DataContext object is in
charge of converting rows to objects and vice versa when
interacting with our conceptual model, a DataContext object
takes a connection string, or any type that implements
IDbConnection as an argument (e.g. SqlConnection). Here is
the code for getting all book titles in the database:
- // ...
- BooksDataContext
db =
new
BooksDataContext(_conn);
- IEnumerable<Book>
query
= from
b
in db.Books
select
b;
- foreach(Book
item
in query)
- {
- Console.WriteLine(item.Title);
- }
- // ...
This code can be associated with the SQL statement:
Select * From Books
Because we only want to select the Title property of the
Book entity we can explicitly define this by returning a new
anonymous type in our query which comprises of just the
Title property of the Book entity.
Because we do not know the type of an anonymous type we
can use the new variant type in C# 3.0. The type of a
variant is inferred by its value, this allows us to use
anonymous types very easily. Below we create a query
variable whose type is inferred by the anonymous type passed
back as a result of the query.
Anonymous types are types which are created at run time; of
what type we do not know, however, the type created has CLR
type safe properties. This code will pass back an anonymous
type with a single property Title which is of type string:
- // ...
- var
query
= from
b
in
db.Books
-
select
new {b.Title};
-
- foreach(var
item
in query)
- {
- Console.WriteLine(item.Title);
- }
- // ...
Next we will look at how we query related entities and look
at the SQL generated by the DataContext to enable these
queries. Because we defined the relationships between our
entities using EntityRef<TEntity>,
and EntitySet<TEntity> we
can access related entities by using dot notation just like
we would do to access methods, or properties of a normal
type. The following query gets the Title of a Book and that
book’s associated PublisherName.
- // ...
- var
books
= from
b
-
in db.Books
select
-
new {b.Title,
b.Publisher.PublisherName};
-
- foreach(var
book
in books)
- {
- Console.WriteLine("Title:
{0}
- Publisher: {1}",
book.Title,
item.PublisherName);
- }
- // ...
We can access the PublisherName property of the Publisher
entity from the Book entity as we have defined the Book
entity as being the parent in the relationship to the
Publisher entity.
For our final query we will get all the authors
associated with each Book. Because there is a set of Author
types associated with a Book we will need to create an inner
loop using a foreach
statement to iterate through the authors associated with any
particular Book. The queries required to achieve this are:
- var
books
= from
b
in
db.Books
select
new {b.Title,
b.Publisher.PublisherName,
b.BookID};
-
- foreach(var
book
in books)
- {
- Console.WriteLine("Title:
{0} Publisher: {1}",
book.Title,
book.PublisherName);
- var
authors
=
from a
in
db.Authors
-
where
a.BookID
==
book.BookID
-
select
new
{a.AuthorName};
- }
-
- foreach(var
author
in
authors)
- {
- Console.WriteLine(author.AuthorName);
- }
LINQ provides a simple set of standard operators to query
in-memory collections as well as entities. LINQ for SQL
allows us to create DAL’s quickly but more importantly they
are more flexible and robust than the common approach we
would take now as demonstrated in the first code snippet.
Hopefully the code examples we have gone through in this
article will provoke you into trying LINQ out for yourself!
If you have any questions, please contact me or post on
the forums.
|