Introduction
This article provides an introduction to employing LINQ to SQL within a Windows Forms application. The article will address the incorporation of LINQ to SQL into a WinForms project, how to use LINQ to SQL to select, insert, update, and delete data, and how to use LINQ to SQL to execute stored procedures. Select query examples will demonstrate ordering, filtering, aggregation, returning typed lists, returning single objects and values, and how to query across entity sets (which are essentially related tables associated by foreign keys).
Figure 1: Application Main Form
The demonstration project included with the article is a simple WinForms application; this example contains a DataGridView
control and a menu; the menu is used to execute each example query contained in the demonstration.
The application provides the following functionality:
- Return Full Tables
- Return Typed Lists
- Return Single Typed Values
- Insert Data
- Update Data
- Delete Data
- Execute Stored Procedures
- Select Filtered Lists
- Select Ordered Lists
- Perform Aggregate Functions
There is a great deal more that one can do with LINQ to SQL that is not contained in this demonstration; however, the demonstration was geared towards the mechanics of performing the most typical types of queries that might be required within a data driven application.
LINQ to SQL Statements
This section will discuss some of the common techniques used in LINQ to SQL statement construction. In a nutshell, LINQ to SQL provides the developer with the means to conduct queries against a relational database through a LINQ to SQL database model and related data context.
Data Context
The data context provides the mapping of all entities (essentially tables) to the database. It is through the data context that the application can query the database, and it is through the data context that changes to the database can be executed.
Anatomy of LINQ to SQL Statements
Example 1 – A Simple Select
This is an example of a very simple LINQ to SQL statement:
public void SimpleQuery()
{
DataClasses1DataContext dc = new DataClasses1DataContext();
var q =
from a in dc.GetTable<Order>()
select a;
dataGridView1.DataSource = q;
}
In the example, an instance of the data context is created, and then a query is formed to get all of the values in the table; once the query runs, the result is used as the data source of a DataGridView
control, and the results are displayed in the grid:
var q =
from a in dc.GetTable<Order>()
select a;
Since the GetTable
function in the data context returns the entire table, this query is pretty useless, but it does work, and it is representative of a simple select
query. You could accomplish the same task using this code:
public void SimpleQuery2()
{
DataClasses1DataContext dc = new DataClasses1DataContext();
dataGridView1.DataSource = dc.GetTable<Order>();
}
If you were to create a project, add either bit of code to a method and run it, the results would look like this:
Figure 2: Query Results
Example 2 – Select with a Where Clause
The next example shows a LINQ to SQL query that incorporates a where
clause. In this example, we get a data context to work with first, and then query the Orders table to find a customer with the customer ID starting with the letter “A”; the results are then bound to a DataGridView
control.
public void SimpleQuery3()
{
DataClasses1DataContext dc = new DataClasses1DataContext();
var q =
from a in dc.GetTable<Order>()
where a.CustomerID.StartsWith("A")
select a;
dataGridView1.DataSource = q;
}
If you were to run the query, the results would appear as follows:
Figure 3: Query Results
Example 3 – Select with a Where Clause
In a slight variation to the previous query, this example looks for an exact match in its where
clause:
public void SimpleQuery3()
{
DataClasses1DataContext dc = new DataClasses1DataContext();
var q =
from a in dc.GetTable<Order>()
where a.CustomerID == "VINET"
select a;
dataGridView1.DataSource = q;
}
Running this code will display this result:
Figure 4: Query Results
Example 4 – Generating an Ordered List
In this query, the list of orders is ordered (using “orderby a.OrderDate ascending
”):
public void SimpleQuery5()
{
DataClasses1DataContext dc = new DataClasses1DataContext();
var q =
from a in dc.GetTable<Order>()
where a.CustomerID.StartsWith("A")
orderby a.OrderDate ascending
select a;
dataGridView1.DataSource = q;
}
Figure 5: Query Results
Example 5 – Working with a Custom Type
In this example, a query is built to return a list of a custom type (CustomerOrderResult
).
public void GetCustomerOrder()
{
DataClasses1DataContext dc = new DataClasses1DataContext();
var q= (from orders in dc.GetTable<Order>()
from orderDetails in dc.GetTable<Order_Detail>()
from prods in dc.GetTable<Product>()
where ((orderDetails.OrderID == orders.OrderID) &&
(prods.ProductID == orderDetails.ProductID) &&
(orders.EmployeeID == 1))
orderby orders.ShipCountry
select new CustomerOrderResult
{
CustomerID = orders.CustomerID,
CustomerContactName = orders.Customer.ContactName,
CustomerCountry = orders.Customer.Country,
OrderDate = orders.OrderDate,
EmployeeID = orders.Employee.EmployeeID,
EmployeeFirstName = orders.Employee.FirstName,
EmployeeLastName = orders.Employee.LastName,
ProductName = prods.ProductName
}).ToList<CustomerOrderResult>();
dataGridView1.DataSource = q;
}
The “select new
” in the query defines the result type, and then sets each of the properties in the type to a value returned by the query. At the end of the query, the output is converted to a List
of the CustomerOrderResult
type.
The displayed results of running the query are:
Figure 6: Query Results
The CustomerOrderResult
class used as the type behind the list is as follows:
public class CustomerOrderResult
{
public System.String CustomerID
{get;set;}
public System.String CustomerContactName
{get;set;}
public System.String CustomerCountry
{get;set;}
public System.Nullable<System.DateTime> OrderDate
{get;set;}
public System.Int32 EmployeeID
{get;set;}
public System.String EmployeeFirstName
{get;set;}
public System.String EmployeeLastName
{get;set;}
public System.String ProductName
{get;set;}
}
Example 6 – Searching an Existing List<T> Using LINQ to Objects
In this example, a typed list is created (as in the previous example) using LINQ to SQL, populated, and then the returned typed list is queried using LINQ to Objects. In this case, the query includes a where
clause that only returns matches were the customer ID begins with “RICAR”:
public void GetCustomerOrder2()
{
DataClasses1DataContext dc = new DataClasses1DataContext();
var query = (from orders in dc.GetTable<Order>()
from orderDetails in dc.GetTable<Order_Detail>()
from prods in dc.GetTable<Product>()
where ((orderDetails.OrderID == orders.OrderID)
&& (prods.ProductID == orderDetails.ProductID)
&& (orders.EmployeeID == 1))
orderby orders.ShipCountry
select new CustomerOrderResult
{
CustomerID = orders.CustomerID,
CustomerContactName = orders.Customer.ContactName,
CustomerCountry = orders.Customer.Country,
OrderDate = orders.OrderDate,
EmployeeID = orders.Employee.EmployeeID,
EmployeeFirstName = orders.Employee.FirstName,
EmployeeLastName = orders.Employee.LastName,
ProductName = prods.ProductName
}).ToList<CustomerOrderResult>();
var matches = (from c in query
where c.CustomerID == "RICAR"
select c).ToList<CustomerOrderResult>();
dataGridView1.DataSource = matches;
}
Figure 7: Query Results
Example 7 – Searching an Existing List<T> Using LINQ to Objects and Returning a Single Result
In this example, a typed list is created (as in the previous example), populated, and then queried using LINQ to Objects. In this case, a single result of type “Parts
” is returned:
public void GetEmployeeLastName()
{
DataClasses1DataContext dc = new DataClasses1DataContext();
var query = (from orders in dc.GetTable<Order>()
select orders);
var matches = (from c in query
where c.OrderID == 10248
select
c.Employee.LastName).SingleOrDefault<System.String>();
MessageBox.Show(matches);
}
The results are displayed as:
Figure 8: Returning a Single Result
The preceding examples were intended to provide a simple overview as to how to conduct some basic queries against collections using LINQ to SQL and LINQ to Objects; there are certainly a great number of more complex operations that can be executed using similar procedures (groups and aggregation, joins, etc.), however, the examples provided are representative of some of the more common types of queries.
Getting Started
There is a single solution included with this download. The solution contains a WinForms project called “LINQSQLCS”; this project contains a form - the main form used to display the results of the demonstration queries (frmMain
), a LINQ to SQL database model (NorthWindDataClasses.dbml) along with the models designer code and the layout file, and a class, “Accessor
”, which contains the code used to perform the LINQ to SQL queries used in the demonstration.
If you open the attached project into Visual Studio 2008, you should see the following in the Solution Explorer:
Figure 9: Solution Explorer
The demonstration relies upon an instance of the Northwind database running in SQL Server 2005. The database can be downloaded from here; the database was created for SQL Server 2000, but you can install the database and attach to it using a local instance of SQL Server 2005.
Once the database is installed, you will want to update the connection string found in the project settings. Open the settings and click on the button (showing an ellipsis) to set the connection string.
Figure 10: Settings and the Connection String
Figure 11: Adding LINQ to SQL Classes to a Project
When starting from scratch, in order to add LINQ to SQL to a project, open the “Add New Item” dialog, and select the LINQ to SQL Classes item (Figure 11); name the data classes and then select the “Add” button to add the item to the project. Once set, set the connection string for the data classes, and then open the Server Explorer to drag tables and stored procedures onto the designer (dragging the tables into the left hand side of the workspace and stored procedures into the right hand side of the workspace (Figure 12)). Once that is done, build the project to generate the LINQ to SQL code.
Figure 12: Model of the Northwind Data Class (tables on left, stored procedures on right)
This project is intended for Visual Studio 2008 with the .NET framework version 3.5.
Code: Accessor.cs
The Accessor
class is used to the store all of the functions used to execute LINQ to SQL queries against the database. The functions contained in this class are all static, and include a mixed bag of selects, inserts, updates, deletes, and stored procedure evocations. You may wish to implement some business logic in the extensibility methods defined in the auto-generated code contained in the designer file, but I chose not to in this example.
The class begins with the normal and default imports:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Linq;
using System.Text;
The next section contains the namespace and class declarations.
namespace LINQSQLCS
{
public class Accessor
{
Next up is a region containing all of the functions used to return full tables from the database through the data context. All of the functions work essentially the same way; the data context includes a function called GetTable<T>
, which is used to return a table of the indicated type. Each example gets a data context, and then evokes the GetTable
function to return the full table of the indicated type.
#region Full Table
public static System.Data.Linq.Table<Employee> GetEmployeeTable()
{
NorthWindDataClassesDataContext dc = new
NorthWindDataClassesDataContext();
return dc.GetTable<Employee>();
}
public static System.Data.Linq.Table<Shipper> GetShipperTable()
{
NorthWindDataClassesDataContext dc = new
NorthWindDataClassesDataContext();
return dc.GetTable<Shipper>();
}
public static System.Data.Linq.Table<Order> GetOrderTable()
{
NorthWindDataClassesDataContext dc = new
NorthWindDataClassesDataContext();
return dc.GetTable<Order>();
}
public static System.Data.Linq.Table<EmployeeTerritory>
GetEmployeeTerritoryTable()
{
NorthWindDataClassesDataContext dc = new
NorthWindDataClassesDataContext();
return dc.GetTable<EmployeeTerritory>();
}
public static System.Data.Linq.Table<Territory> GetTerritoryTable()
{
NorthWindDataClassesDataContext dc = new
NorthWindDataClassesDataContext();
return dc.GetTable<Territory>();
}
public static System.Data.Linq.Table<Region> GetRegionTable()
{
NorthWindDataClassesDataContext dc = new
NorthWindDataClassesDataContext();
return dc.GetTable<Region>();
}
public static System.Data.Linq.Table<Customer> GetCustomerTable()
{
NorthWindDataClassesDataContext dc = new
NorthWindDataClassesDataContext();
return dc.GetTable<Customer>();
}
public static System.Data.Linq.Table<CustomerCustomerDemo>
GetCustomerDemoTable()
{
NorthWindDataClassesDataContext dc = new
NorthWindDataClassesDataContext();
return dc.GetTable<CustomerCustomerDemo>();
}
public static System.Data.Linq.Table<CustomerDemographic>
GetCustomerDemographicTable()
{
NorthWindDataClassesDataContext dc = new
NorthWindDataClassesDataContext();
return dc.GetTable<CustomerDemographic>();
}
public static System.Data.Linq.Table<Order_Detail> GetOrderDetailsTable()
{
NorthWindDataClassesDataContext dc = new
NorthWindDataClassesDataContext();
return dc.GetTable<Order_Detail>();
}
public static System.Data.Linq.Table<Product> GetProductTable()
{
NorthWindDataClassesDataContext dc = new
NorthWindDataClassesDataContext();
return dc.GetTable<Product>();
}
public static System.Data.Linq.Table<Supplier> GetSupplierTable()
{
NorthWindDataClassesDataContext dc = new
NorthWindDataClassesDataContext();
return dc.GetTable<Supplier>();
}
public static System.Data.Linq.Table<Category> GetCategoryTable()
{
NorthWindDataClassesDataContext dc = new
NorthWindDataClassesDataContext();
return dc.GetTable<Category>();
}
#endregion
That next region contained in the Accessor
class is the Queries region; this region contains examples of different types of select queries that may be performed using LINQ to SQL. Each query is described in the annotation:
#region Queries
public static Employee GetEmployeeById(int empId)
{
NorthWindDataClassesDataContext dc = new
NorthWindDataClassesDataContext();
return (from e in dc.GetTable<Employee>()
where (e.EmployeeID == empId)
select e).SingleOrDefault<Employee>();
}
public static Order GetOrderById(int orderId)
{
NorthWindDataClassesDataContext dc = new
NorthWindDataClassesDataContext();
return (from ord in dc.GetTable<Order>()
where (ord.OrderID == orderId)
select ord).SingleOrDefault<Order>();
}
public static List<Order> GetOrdersById(int orderId)
{
NorthWindDataClassesDataContext dc = new
NorthWindDataClassesDataContext();
return (from ord in dc.GetTable<Order>()
where (ord.OrderID == orderId)
select ord).ToList<Order>();
}
public static List<Employee> GetEmployeesByHireDate()
{
NorthWindDataClassesDataContext dc = new
NorthWindDataClassesDataContext();
return (from emp in dc.GetTable<Employee>()
orderby emp.HireDate ascending
select emp).ToList<Employee>();
}
public class OrdersAndDetailsResult
{
public System.String CustomerID
{ get; set; }
public System.Nullable<System.DateTime> OrderDate
{ get; set; }
public System.Nullable<System.DateTime> RequiredDate
{ get; set; }
public System.String ShipAddress
{ get; set; }
public System.String ShipCity
{ get; set; }
public System.String ShipCountry
{ get; set; }
public System.String ShipZip
{ get; set; }
public System.String ShippedTo
{ get; set; }
public System.Int32 OrderID
{ get; set; }
public System.String NameOfProduct
{ get; set; }
public System.String QtyPerUnit
{ get; set; }
public System.Nullable<System.Decimal> Price
{ get; set; }
public System.Int16 QtyOrdered
{ get; set; }
public System.Single Discount
{ get; set; }
}
public static List<OrdersAndDetailsResult> OrdersAndDetails()
{
NorthWindDataClassesDataContext dc = new
NorthWindDataClassesDataContext();
return (from ords in dc.GetTable<Order>()
join dets in dc.GetTable<Order_Detail>()
on ords.OrderID equals dets.OrderID
orderby ords.CustomerID ascending
select new OrdersAndDetailsResult
{
CustomerID = ords.CustomerID,
OrderDate = ords.OrderDate,
RequiredDate = ords.RequiredDate,
ShipAddress = ords.ShipAddress,
ShipCity = ords.ShipCity,
ShipCountry = ords.ShipCountry,
ShipZip = ords.ShipPostalCode,
ShippedTo = ords.ShipName,
OrderID = ords.OrderID,
NameOfProduct = dets.Product.ProductName,
QtyPerUnit = dets.Product.QuantityPerUnit,
Price = dets.Product.UnitPrice,
QtyOrdered = dets.Quantity,
Discount = dets.Discount
}
).ToList <OrdersAndDetailsResult>();
}
public class OrderandPricingResult
{
public System.Int32 OrderID
{ get; set; }
public System.String Company
{ get; set; }
public System.String OrderCountry
{ get; set; }
public System.String ProductName
{ get; set; }
public System.Nullable<System.Decimal> UnitPrice
{ get; set; }
public System.Int16 UnitsOrder
{ get; set; }
public System.String ShipperName
{ get; set; }
public System.String SalesFirstName
{ get; set; }
public System.String SalesLastName
{ get; set; }
public System.String SalesTitle
{ get; set; }
}
public static List<OrderandPricingResult> GetOrderAndPricingInformation()
{
NorthWindDataClassesDataContext dc = new
NorthWindDataClassesDataContext();
return (from ords in dc.Orders
from dets in ords.Order_Details
select new OrderandPricingResult
{
OrderID = ords.OrderID,
Company =ords.Customer.CompanyName,
OrderCountry = ords.Customer.Country,
ProductName = dets.Product.ProductName,
UnitPrice = dets.Product.UnitPrice,
UnitsOrder = dets.Quantity,
ShipperName = ords.Shipper.CompanyName,
SalesFirstName = ords.Employee.FirstName,
SalesLastName = ords.Employee.LastName,
SalesTitle = ords.Employee.Title
}).ToList < OrderandPricingResult>();
}
public static List<OrderandPricingResult>
GetOrderAndPricingInformationByOrderId(int orderId)
{
NorthWindDataClassesDataContext dc = new
NorthWindDataClassesDataContext();
return (from ords in dc.Orders
from dets in ords.Order_Details
where ords.OrderID == orderId
select new OrderandPricingResult
{
OrderID = ords.OrderID,
Company = ords.Customer.CompanyName,
OrderCountry = ords.Customer.Country,
ProductName = dets.Product.ProductName,
UnitPrice = dets.Product.UnitPrice,
UnitsOrder = dets.Quantity,
ShipperName = ords.Shipper.CompanyName,
SalesFirstName = ords.Employee.FirstName,
SalesLastName = ords.Employee.LastName,
SalesTitle = ords.Employee.Title
}).ToList<OrderandPricingResult>();
}
public static decimal? GetOrderValueByOrderId(int orderID)
{
NorthWindDataClassesDataContext dc = new
NorthWindDataClassesDataContext();
var matches =
(from od in dc.GetTable<Order_Detail>()
where od.OrderID == orderID
select od.Product.UnitPrice * od.Quantity).Sum();
return matches;
}
public static List<Order> GetTopFiveOrdersById(int SkipNumber)
{
NorthWindDataClassesDataContext dc = new
NorthWindDataClassesDataContext();
return (from ord in dc.GetTable<Order>()
orderby ord.OrderID ascending
select ord).Skip(SkipNumber).Take(5).ToList<Order>();
}
#endregion
The next region is “Inserting, Updating, and Deleting Data”; it contains examples of how to insert or update data, and an example showing how to delete data from the database. Each function is described in its annotation:
#region Inserting, Updating, Deleting Data
public static void InsertOrUpdateCustomer(string customerId, string
companyName, string contactName, string contactTitle, string address,
string city, string region, string postalCode, string country, string
phone, string
fax)
{
NorthWindDataClassesDataContext dc = new
NorthWindDataClassesDataContext();
var matchedCustomer = (from c in dc.GetTable<Customer>()
where c.CustomerID == customerId
select c).SingleOrDefault();
if(matchedCustomer == null)
{
try
{
Table<Customer> customers = Accessor.GetCustomerTable();
Customer cust = new Customer();
cust.CustomerID = customerId;
cust.CompanyName = companyName;
cust.ContactName = contactName;
cust.ContactTitle = contactTitle;
cust.Address = address;
cust.City = city;
cust.Region = region;
cust.PostalCode = postalCode;
cust.Country = country;
cust.Phone = phone;
cust.Fax = fax;
customers.InsertOnSubmit(cust);
customers.Context.SubmitChanges();
}
catch (Exception ex)
{
throw ex;
}
}
else
{
try
{
matchedCustomer.CompanyName = companyName;
matchedCustomer.ContactName = contactName;
matchedCustomer.ContactTitle = contactTitle;
matchedCustomer.Address = address;
matchedCustomer.City = city;
matchedCustomer.Region = region;
matchedCustomer.PostalCode = postalCode;
matchedCustomer.Country = country;
matchedCustomer.Phone = phone;
matchedCustomer.Fax = fax;
dc.SubmitChanges();
}
catch (Exception ex)
{
throw ex;
}
}
}
public static void DeleteCustomer(string customerID)
{
NorthWindDataClassesDataContext dc = new
NorthWindDataClassesDataContext();
var matchedCustomer = (from c in dc.GetTable<Customer>()
where c.CustomerID == customerID
select c).SingleOrDefault();
try
{
dc.Customers.DeleteOnSubmit(matchedCustomer);
dc.SubmitChanges();
}
catch (Exception ex)
{
throw ex;
}
}
#endregion
The last region of the class contains the code used to execute stored procedures. The stored procedures, once added to the project, may be immediately accessed through the data context; to access a stored procedure, just get an instance of the data context and call the stored procedure, passing along any required parameters as arguments to the function call:
#region Stored Procedures
public static List<Sales_by_YearResult> SalesByYear(DateTime? beginningYear,
DateTime? endingYear)
{
NorthWindDataClassesDataContext dc = new
NorthWindDataClassesDataContext();
return dc.Sales_by_Year(beginningYear,
endingYear).ToList<Sales_by_YearResult>();
}
public static List<Ten_Most_Expensive_ProductsResult>
TenMostExpensiveProducts()
{
NorthWindDataClassesDataContext dc = new
NorthWindDataClassesDataContext();
return
dc.Ten_Most_Expensive_Products().ToList<Ten_Most_Expensive_ProductsResult>();
}
#endregion
That concludes the description of the “Accessor
” class.
Code: Main Application Form (frmMain.cs)
This is the main form of the application; this form is used to provide a test harness for testing each of the functions defined in the Accessor
class. All functions defined in the Accessor
class have a corresponding menu item, and the Click
event handler for each menu item executes an Accessor
class function, supplying any arguments necessary as canned values.
The structure for the main form’s menu is as follows:
- Menu
- File
- Read
- Tables
- Queries
- Stored Procedures
- Insert/Update/Delete
Figure 13: frmMain.cs
The class begins with the normal and default imports:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
The next section contains the namespace and class declarations.
namespace LINQSQLCS
{
public partial class frmMain : Form
{
Next is the definition of a private variable used to maintain the position within the orders table; it is used in an example showing how to make use of the Skip
and Take
functions.
private int OrderPosition;
The next region of code in the class contains the constructor. The constructor sets the OrderPosition
integer value to zero.
#region Constructor
public frmMain()
{
InitializeComponent();
OrderPosition = 0;
}
#endregion
The next code region is called ‘Full Table Requests’. Each of the functions operates in a similar manner in that a function creates a list of the type returned by the Accessor
class function called, evokes the Accessor
function, and then assigns the returned list to the data source property of the DataGridView
control contained in the main form.
#region Full Table Requests
private void employeesToolStripMenuItem_Click(object sender, EventArgs e)
{
System.Data.Linq.Table<Employee> emp = Accessor.GetEmployeeTable();
dataGridView1.DataSource = emp;
}
private void shippersToolStripMenuItem_Click(object sender, EventArgs e)
{
System.Data.Linq.Table<Shipper> ship = Accessor.GetShipperTable();
dataGridView1.DataSource = ship;
}
private void ordersToolStripMenuItem_Click(object sender, EventArgs e)
{
System.Data.Linq.Table<Order> orders = Accessor.GetOrderTable();
dataGridView1.DataSource = orders;
}
private void employeeTerritoryToolStripMenuItem_Click(object sender,
EventArgs e)
{
System.Data.Linq.Table<EmployeeTerritory> empTerrs =
Accessor.GetEmployeeTerritoryTable();
dataGridView1.DataSource = empTerrs;
}
private void territoryToolStripMenuItem_Click(object sender, EventArgs e)
{
System.Data.Linq.Table<Territory> terrs = Accessor.GetTerritoryTable();
dataGridView1.DataSource = terrs;
}
private void regionToolStripMenuItem_Click(object sender, EventArgs e)
{
System.Data.Linq.Table<Region> regs = Accessor.GetRegionTable();
dataGridView1.DataSource = regs;
}
private void customerToolStripMenuItem_Click(object sender, EventArgs e)
{
System.Data.Linq.Table<Customer> cust = Accessor.GetCustomerTable();
dataGridView1.DataSource = cust;
}
private void customerDemoToolStripMenuItem_Click(object sender, EventArgs e)
{
System.Data.Linq.Table<CustomerCustomerDemo> custdemo =
Accessor.GetCustomerDemoTable();
dataGridView1.DataSource = custdemo;
}
private void customerDemographicToolStripMenuItem_Click(object sender,
EventArgs e)
{
System.Data.Linq.Table<CustomerDemographic> custdemograph =
Accessor.GetCustomerDemographicTable();
dataGridView1.DataSource = custdemograph;
}
private void orderDetailsToolStripMenuItem_Click(object sender, EventArgs e)
{
System.Data.Linq.Table<Order_Detail> ordDetails =
Accessor.GetOrderDetailsTable();
dataGridView1.DataSource = ordDetails;
}
private void productToolStripMenuItem_Click(object sender, EventArgs e)
{
System.Data.Linq.Table<Product> prods = Accessor.GetProductTable();
dataGridView1.DataSource = prods;
}
private void supplierProductToolStripMenuItem_Click(object sender, EventArgs e)
{
System.Data.Linq.Table<Supplier> prods = Accessor.GetSupplierTable();
dataGridView1.DataSource = prods;
}
private void categoToolStripMenuItem_Click(object sender, EventArgs e)
{
System.Data.Linq.Table<Category> cats = Accessor.GetCategoryTable();
dataGridView1.DataSource = cats;
}
#endregion
The next region contains the menu item Click
event handlers used to execute each of the queries described in the queries region of the Accessor
class. Each function is annotated to describe what it does and what it is intended to demonstrate.
#region Queries
private void employeeByIDToolStripMenuItem_Click(object sender, EventArgs e)
{
Employee emp = Accessor.GetEmployeeById(1);
StringBuilder sb = new StringBuilder();
sb.Append("Employee 1: " + Environment.NewLine);
sb.Append("Name: " + emp.FirstName + " " + emp.LastName +
Environment.NewLine);
sb.Append("Hire Date: " + emp.HireDate + Environment.NewLine);
sb.Append("Home Phone: " + emp.HomePhone + Environment.NewLine);
MessageBox.Show(sb.ToString(), "Employee ID Search");
}
private void orderByIDToolStripMenuItem_Click(object sender, EventArgs e)
{
Order ord = Accessor.GetOrderById(10248);
StringBuilder sb = new StringBuilder();
sb.Append("Order: " + Environment.NewLine);
sb.Append("Order ID: " + ord.OrderID + Environment.NewLine);
sb.Append("Date Shipped: " + ord.ShippedDate + Environment.NewLine);
sb.Append("Shipping Address: " + ord.ShipAddress + Environment.NewLine);
sb.Append(" City: " + ord.ShipCity + Environment.NewLine);
sb.Append(" Region: " + ord.ShipRegion + Environment.NewLine);
sb.Append(" Country: " + ord.ShipCountry + Environment.NewLine);
sb.Append(" Postal Code: " + ord.ShipPostalCode + Environment.NewLine);
sb.Append("Shipping Name: " + ord.ShipName + Environment.NewLine);
MessageBox.Show(sb.ToString(), "Shipping Information");
}
private void employeesByHireDateToolStripMenuItem_Click(object sender,
EventArgs e)
{
List<Employee> emps = Accessor.GetEmployeesByHireDate();
dataGridView1.DataSource = emps;
}
private void ordersByIdToolStripMenuItem_Click(object sender, EventArgs e)
{
List<Order> orders = Accessor.GetOrdersById(10248);
dataGridView1.DataSource = orders;
}
private void ordersAndDetailsToolStripMenuItem_Click(object sender,
EventArgs e)
{
List<Accessor.OrdersAndDetailsResult> oad = Accessor.OrdersAndDetails();
dataGridView1.DataSource = oad;
}
private void ordersAndDetailsEntityRefToolStripMenuItem_Click(object sender,
EventArgs e)
{
List<Accessor.OrderandPricingResult> opr =
Accessor.GetOrderAndPricingInformation();
dataGridView1.DataSource = opr;
}
private void ordersAndDetailsByOrderIDEntityRefToolStripMenuItem_Click(object
sender, EventArgs e)
{
List<Accessor.OrderandPricingResult> opr =
Accessor.GetOrderAndPricingInformationByOrderId(10248);
dataGridView1.DataSource = opr;
}
private void orderValueByOrderIDToolStripMenuItem_Click(object sender,
EventArgs e)
{
decimal? d = Accessor.GetOrderValueByOrderId(10248);
string dollarValue = string.Format("{0:c}", d);
MessageBox.Show("The total dollar value of order 10248 is " +
dollarValue, "Order 10248 Value");
}
private void getTopFiveOrdersToolStripMenuItem_Click(object sender,
EventArgs e)
{
try
{
List<Order> ords = Accessor.GetTopFiveOrdersById(OrderPosition);
dataGridView1.DataSource = ords;
OrderPosition += 5;
getTopFiveOrdersToolStripMenuItem.Text = "Get Next Five Orders";
}
catch
{
MessageBox.Show("Cannot increment an higher, starting list over.");
OrderPosition = 0;
}
}
#endregion
The next region contains methods used to insert, update, or delete data from the database; these Click
event handlers evoke the corresponding functions contained in the Accessor
class:
#region Insert Update Delete
The Insert or Update Customer menu item Click
event handler calls the Accessor
class InsertOrUpdateCustomer
function, passing in some canned arguments to populate the list. If you look at the customer table before and after executing this Click
event handler, you will see the customer added to the table.
private void insertOrUpdateCustomerToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
Accessor.InsertOrUpdateCustomer("AAAAA", "BXSW", "Mookie Carbunkle", "Chieftain",
"122 North Main Street", "Wamucka", "DC", "78888",
"USA", "244-233-8977",
"244-438-2933");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error");
}
}
The Delete Customer menu item Click
event handler is used to delete the customer created by running the previous function; again, checking the table before and after running this Click
event handler will allow you to see the added customer deleted from the table.
private void deleteCustomerToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
Accessor.DeleteCustomer("AAAAA");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error");
}
}
#endregion
The final region in this class is used to execute a couple of the stored procedures made available through the data context.
#region Stored Procedures
private void salesByYearToolStripMenuItem_Click(object sender, EventArgs e)
{
DateTime start = new DateTime(1990, 1, 1);
DateTime end = new DateTime(2000, 1, 1);
List<Sales_by_YearResult> result = Accessor.SalesByYear(start, end);
dataGridView1.DataSource = result;
}
private void tenMostExpensiveProductsToolStripMenuItem_Click(object sender,
EventArgs e)
{
List<Ten_Most_Expensive_ProductsResult> result =
Accessor.TenMostExpensiveProducts();
dataGridView1.DataSource = result;
}
#endregion
The last region contained in the class is the Housekeeping region; in this region, there is only one Click
event handler which is used to exit the application.
#region Housekeeping
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
Application.Exit();
}
#endregion
Summary
The article shows some simple examples of LINQ to SQL; from it, you can see how easy it is to query against single and related tables and to write filtered queries, execute stored procedures, perform aggregation, and how to insert, update, and delete records from the database.