Introduction to LINQ to SQL
Basic Introduction to Mapping Entities using LINQ to SQL
Updated: 03 September 2023
Note that you can follow this entire process or skip to the Shortcut section at the end
Using the Microsoft docs on LINQ to SQL and the sample database setup script
You will also need Visual Studio installed
Create the Database
To get started first create the database based on the Script above by applying it from SQL Server Management Server or another database management tool
Typical Process
The typical process for a LINQ to SQL application development is as follows:
- Create a model class and execute simple queries
- Add additional classes and execute more complex queries
- Add, change, and delete database items
- Use Stored Procedures
1. Model Setup and Single Entity Query
Configure the Project
- In Visual Studio create a new .NET Framework Console App called
LinqToSql
- From the Solution Explorer right click on the Project and select
References > Add Reference
and add a reference toSystem.Data.Linq
from theFramework
section - Add the following
usings
to theProgram.cs
file:
1using System.Data.Linq;
Mapping a Class to Database Table
Now we can create a new class and map it to our database table. Create a file in the Project called Models/Customer.cs
with the following class definition. This states that the Table Name for our Customer
collection is Customer
1[Table(Name = "Customers")]2public class Customer { }
In the class body we can reference the different columns as well as the private internal variable that will hold the value, this is referenced by the Column Annotation, don’t collapse it to a single property (even if Visual Studio tells you to). We can see the full Customer.cs
file below:
1using System.Data.Linq.Mapping;2
3namespace LinqToSql.Models4{5 [Table(Name = "Customers")]6 public class Customer7 {8 private string _CustomerID;9 [Column(IsPrimaryKey = true, Storage = "_CustomerID")]10 public string CustomerID11 {12 get13 {14 return this._CustomerID;15 }16 set17 {18 this._CustomerID = value;19 }20
21 }22
23 private string _City;24 [Column(Storage = "_City")]25 public string City26 {27 get28 {29 return this._City;30 }31 set32 {33 this._City = value;34 }35 }36 }37}
Query Database
We need to create a link to our database using a DataContext
object. The documentation makes use of the connection to the mdf
file, however we’ll use a ConnectionString
instead as this makes more sense in practice
We can create a new DataContext
as follows
1DataContext db = new DataContext("<ConnectionString>")
Thereafter we can query a table in our db
object by using the db.GetTable
function
1Table<Customer> customers = db.GetTable<Customer>();
Using our customers
object we can make queries against the table with:
1IQueryable<Customer> custQuery = customers.Where(c => c.City == "London");
And print out the reqults of the query with:
1foreach (Customer c in custQuery)2{3 Console.WriteLine("ID={0}, City={1}", c.CustomerID, c.City);4}
Putting this all together, our Program.cs
file should now contain the following:
1using LinqToSql.Models;2using System;3using System.Data.Linq;4using System.Linq;5
6namespace LinqToSql7{8 class Program9 {10 static void Main(string[] args)11 {12 DataContext db = new DataContext(@"Data Source=localhost\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True");13
14 db.Log = Console.Out;15
16 Table<Customer> customers = db.GetTable<Customer>();17
18 IQueryable<Customer> custQuery = customers.Where(c => c.City == "London");19
20 foreach (Customer c in custQuery)21 {22 Console.WriteLine("ID={0}, City={1}", c.CustomerID, c.City);23 }24
25 Console.ReadLine();26 }27 }28}
2. Query Across Relationships
Update the Data Model
First, create the Models/Order.cs
file with the following content:
1using System.Data.Linq;2using System.Data.Linq.Mapping;3
4namespace LinqToSql.Models5{6 [Table(Name = "Orders")]7 public class Order8 {9 private int _OrderID = 0;10 private string _CustomerID;11 private EntityRef<Customer> _Customer;12 public Order() { this._Customer = new EntityRef<Customer>(); }13
14 [Column(Storage = "_OrderID", DbType = "Int NOT NULL IDENTITY",15 IsPrimaryKey = true, IsDbGenerated = true)]16 public int OrderID17 {18 get { return this._OrderID; }19 }20
21 [Column(Storage = "_CustomerID", DbType = "NChar(5)")]22 public string CustomerID23 {24 get { return this._CustomerID; }25 set { this._CustomerID = value; }26 }27
28 [Association(Storage = "_Customer", ThisKey = "CustomerID")]29 public Customer Customer30 {31 get { return this._Customer.Entity; }32 set { this._Customer.Entity = value; }33 }34 }35}
Note that in the
Order
model we do not have a getter for theOrderId
as this is generated by the database and cannot be set
Next we should add a reference to the Order
model from the Customer
model so as to make it easier to navigate the relationship. We can do this by dding a reference to the Order
entity in our constructor:
1public Customer()2{3 this._Orders = new EntitySet<Order>();4}
And then adding the Orders
property on the field:
1private EntitySet<Order> _Orders;2[Association(Storage = "_Orders", OtherKey = "CustomerID")]3public EntitySet<Order> Orders4{5 get6 {7 return this._Orders;8 }9 set10 {11 this._Orders.Assign(value);12 }13}
Finally the Customer.cs
file should be as follows:
1using System.Data.Linq;2using System.Data.Linq.Mapping;3
4namespace LinqToSql.Models5{6 [Table(Name = "Customers")]7 public class Customer8 {9 public Customer()10 {11 this._Orders = new EntitySet<Order>();12 }13
14 private string _CustomerID;15 [Column(IsPrimaryKey = true, Storage = "_CustomerID")]16 public string CustomerID17 {18 get19 {20 return this._CustomerID;21 }22 set23 {24 this._CustomerID = value;25 }26
27 }28
29 private string _City;30 [Column(Storage = "_City")]31 public string City32 {33 get34 {35 return this._City;36 }37 set38 {39 this._City = value;40 }41 }42
43 private EntitySet<Order> _Orders;44 [Association(Storage = "_Orders", OtherKey = "CustomerID")]45 public EntitySet<Order> Orders46 {47 get48 {49 return this._Orders;50 }51 set52 {53 this._Orders.Assign(value);54 }55 }56 }57}
Query Across Multiple Entities
Now we can query this data from the Program.cs
file with a query like the following:
1IQueryable<Customer> custOrderQuery = db.Customers.Where(c => c.Orders.Any());2
3foreach (Customer c in custOrderQuery)4{5 Console.WriteLine("ID={0}, City={1}, Orders={2}", c.CustomerID, c.City, c.Orders.Count);6}
Create a Strongly Typed Database View
It can be easier to create a strongly typed view of the database by creating a DataContext
object that we define instead of using the GetTable
function to retrieve a specific table
Create a class called NorthwindContext
with the following code containing a definition for Customers
and Orders
:
1using System.Data.Linq;2
3namespace LinqToSql.Models4{5 public class NorthwindContext : DataContext6 {7 // Table<T> abstracts database details per table/data type.8 public Table<Customer> Customers;9 public Table<Order> Orders;10
11 public Northwind(string connection) : base(connection) { }12 }13}
We can now replace DbContext
definition with NorthwindContext
and the call to GetTable
to just use the Customers
property in the NorthwindContext
class like so:
1NorthwindContext db = new NorthwindContext(@"Data Source=localhost\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True");2
3IQueryable<Customer> custQuery = db.Customers.Where(c => c.City == "London");
As well as in our second query:
1IQueryable<Customer> custOrderQuery = db.Customers.Where(c => c.Orders.Any());
3. Manipulating Data
To manipulate data we can use some of the functions provided to us by LINQ to SQL
We can update data in our database by followind a few basic steps
- Retreive the entity we want to modify
- Create, Update, or Delete the entity
- Submit changes to the datbase
Retrieve an Entity
We can retrieve an entity by wuerying the database for it
1Customer custToUpdate = db.Customers.Where(c => c.Orders.Any()).First();
Modify Entity
Next you we can modify the City
and delete an Order
from the customer
1custToUpdate.City = "NEW CITY";2
3db.Orders.DeleteOnSubmit(custToUpdate.Orders[0]);
Submit Changes
Lastly we can submit the changes to the database
1db.SubmitChanges();
4. Using Stored Procedures
In order to use existing Stored Procedures you can make use of the SQLMetal
tool or using the Object Relational Designer
in Visual Studio
Getting Started with the O/R Designer
First, create a new Linq to SQL Class
file from the Right Click Project > Add New Item
dialog, you can call the file DataClasses.dbml
Next add a link to the Database you are working with from the Server Explorer in Visual Studio and you can drag in the Customers
and Orders
table and the relationship should be visible and this should update the generated DataContext
classes with the information you update in the designer. This will not update the database
The O/R Designer only supports 1:1 mappings
You can modify and update information in this view although I would suggest doing it from the
Creating Methods from Stored Procedures can be done by pulling them in from the Stored Procedures
folder on the DB to the methods
section on the designer view
Shortcut
You don’t need to do all the above manually. From Visual Studio do the following:
- Create the project
- Open the database in the Server Explorer
- Add a LinqToSQL Class file (
.dbml
) - Drag in the tables you would like to work and it will generate the