Toward the bottom of the LINQ to SQL samples, you'll find several methods discussing the DataContext class. This is an important class that provides the interface between your code and the physical database storage.
There are also some convenient methods that can make it easier for you to initialize a LINQ-enabled application for the first time.
One of the startup tasks would be to check for a database's existence, and create that database if necessary.
This snippet of code shows you how to initialize a DataContext – derived object and determine if the corresponding database exists:
string userTempFolder = Environment.GetEnvironmentVariable("Temp");
string userMDF = System.IO.Path.Combine(userTempFolder, @"NewCreateDB.mdf");
NewCreateDB newDB = new NewCreateDB(userMDF);
if (newDB.DatabaseExists())
Console.WriteLine("Error: NewCreateDB DB exists");
else
Console.WriteLine("NewCreateDB DB does not exist");
The code above creates a string representing the path to a database, and creates a DataContext for that database. Once the context is created, the DatabaseExists () method will tell you if the database exists.
Of course, if the database doesn't exist, you probably want to create it:
NewCreateDB newDB = new NewCreateDB(connStr);
newDB.CreateDatabase();
And, just because you might need to, you can delete the database:
newDB.DeleteDatabase();
For debugging purposes, the DataContext class contains a Log property that if set to a valid stream, will provide trace information that you can use to understand the underlying code in your LINQ to SQL applications.
db.Log = this.OutputStreamWriter;
To turn it off, just set the Log property to null:
db.Log = null;
Finally, I'll provide a glimpse into some of the topics I'll cover in one of my talks at CodeMash: IQueryProvider and how some of the underlying LINQ capabilities are provided for you by a datasource.
Here's a rather advanced bit of code that builds a query:
var c1 = Expression.Parameter(typeof(Customer), "c");
PropertyInfo City = typeof(Customer).GetProperty("City");
var pred = Expression.Lambda<Func<Customer, bool>>(
Expression.Equal(
Expression.Property(c1, City),
Expression.Constant("Seattle")
), c1
);
IQueryable custs = db.Customers;
Expression expr = Expression.Call(typeof(Queryable), "Where",
new Type[] { custs.ElementType }, custs.Expression, pred);
IQueryable<Customer> q =
db.Customers.AsQueryable().Provider.CreateQuery<Customer>(expr);
The purpose of the code is to build a query, or a set of code as an Expression which can be parsed, compiled, or executed. It's the key to treating code as data in LINQ.
The first two lines show a bit of low-level grunt code necessary to build a query. The first line initializes c1 to an Expression object that represents a parameter. The name of the parameter is 'c', and the type of the parameter is a customer. That's a rather simply example of an expression (a ParameterExpression, to be precise).
The next line finds the PropertyInfo object representing the 'City' property of a customer. That should be clear to anyone that has used Reflection in the past.
Now comes the cool part. The predicate, 'pred', defines the lambda expression that finds all customers where the city is Seattle. It's the code that gets built when you write "from c in Customers where c.City == Seattle". Pred is an Expression<Func<Customer,bool>>. That means it is an expression which contains a function that has one parameter (of type Customer), and returns a Boolean. The body of the lambda compares the city property to the constant "Seattle". Fun, huh?
Well, now you can execute the expression. Custs is the Customers table as an IQueryable. IQueryable behaves (on the outside) similar to the IEnumerable interface. However, IQueryable provides some extra goodness.
That extra goodness is the ability to take an expression and execute it. First, you need to define the expression. That next line of code creates a method call expression on the Customers table, using the predicate defined a bit earlier, and the "Where" method.
The last line creates a query using that expression on the customers table.
It's complicated code, but it's important to understand from the standpoint of running queries in the most efficient way. An implementor of IQueryable can determine the best way to implement the algorithm defined by a query expression. In the case of LINQ to SQL, this is the mechanism that is used to translate your lambda expressions and methods into T-SQL code that is executed in the database engine.