Querying Data with LINQ to SQL
This section delves into the core functionality of LINQ to SQL: querying data from a relational database using Language Integrated Query (LINQ). LINQ to SQL provides a straightforward way to map database tables and views to .NET objects and to express queries against this data using familiar LINQ syntax.
Understanding the DataContext
The DataContext
is the central class in LINQ to SQL. It represents a connection to the database and is responsible for managing objects, tracking changes, and executing queries. You typically create an instance of DataContext
to interact with your database.
For example, assuming you have a database connection string and a mapping defined:
using System.Linq;
using YourNamespace.Database; // Assuming your generated DataContext resides here
public class DataQueryService
{
private readonly YourDatabaseDataContext _db;
public DataQueryService(string connectionString)
{
_db = new YourDatabaseDataContext(connectionString);
}
// ... query methods will go here
}
Basic Querying
LINQ to SQL allows you to write queries using method syntax or query syntax. Both translate to SQL at runtime.
Retrieving All Records
To retrieve all records from a table, you can access the corresponding Table<TEntity>
property on your DataContext
.
// Example: Get all customers
var allCustomers = _db.Customers.ToList();
Filtering Data (WHERE Clause)
The Where()
extension method is used to filter data based on specified conditions, which translates to a SQL WHERE
clause.
// Example: Get customers from London
var londonCustomers = _db.Customers.Where(c => c.City == "London").ToList();
// Using query syntax:
var londonCustomersQuery = from c in _db.Customers
where c.City == "London"
select c;
var londonCustomersList = londonCustomersQuery.ToList();
Sorting Data (ORDER BY Clause)
The OrderBy()
and OrderByDescending()
methods are used for sorting, mapping to SQL's ORDER BY
clause.
// Example: Get customers sorted by name
var sortedCustomers = _db.Customers.OrderBy(c => c.CompanyName).ToList();
// Example: Get customers sorted by name in descending order
var sortedCustomersDesc = _db.Customers.OrderByDescending(c => c.CompanyName).ToList();
Selecting Specific Columns (SELECT Clause)
You can project query results into new object types or anonymous types using the Select()
method.
// Example: Get only the names and cities of customers
var customerNamesAndCities = _db.Customers.Select(c => new { c.CompanyName, c.City }).ToList();
// Using query syntax:
var customerNamesAndCitiesQuery = from c in _db.Customers
select new { c.CompanyName, c.City };
var customerNamesAndCitiesList = customerNamesAndCitiesQuery.ToList();
Joining Tables (JOIN Clause)
LINQ to SQL supports joining multiple tables using the Join()
method or the join
keyword in query syntax.
// Example: Get orders along with customer names
var ordersWithCustomerNames = _db.Orders.Join(
_db.Customers,
order => order.CustomerID,
customer => customer.CustomerID,
(order, customer) => new { OrderID = order.OrderID, CustomerName = customer.CompanyName, OrderDate = order.OrderDate }
).ToList();
// Using query syntax:
var ordersWithCustomerNamesQuery = from o in _db.Orders
join c in _db.Customers on o.CustomerID equals c.CustomerID
select new { OrderID = o.OrderID, CustomerName = c.CompanyName, OrderDate = o.OrderDate };
var ordersWithCustomerNamesList = ordersWithCustomerNamesQuery.ToList();
Grouping Data (GROUP BY Clause)
The GroupBy()
method allows you to group data based on a specified key.
// Example: Group customers by city
var customersGroupedByCity = _db.Customers
.GroupBy(c => c.City)
.Select(g => new { City = g.Key, Count = g.Count() })
.ToList();
// Using query syntax:
var customersGroupedByCityQuery = from c in _db.Customers
group c by c.City into g
select new { City = g.Key, Count = g.Count() };
var customersGroupedByCityList = customersGroupedByCityQuery.ToList();
Aggregation Functions
LINQ to SQL supports common aggregation functions like Count()
, Sum()
, Average()
, Min()
, and Max()
.
// Example: Count total orders
int totalOrders = _db.Orders.Count();
// Example: Calculate the total quantity of a specific product ordered
int productIdToCalculate = 1;
decimal totalQuantity = _db.OrderDetails
.Where(od => od.ProductID == productIdToCalculate)
.Sum(od => od.Quantity);
// Example: Find the highest unit price
decimal highestUnitPrice = _db.Products.Max(p => p.UnitPrice);
ToList()
, ToArray()
, or iterate over the results, the actual SQL query is generated and sent to the database.
Lazy Loading and Eager Loading
LINQ to SQL supports lazy loading by default, where related data is fetched only when it's accessed. You can also explicitly configure eager loading for performance benefits in certain scenarios.
To enable eager loading, you can use the LoadWith
option:
// Example: Eagerly load customers along with their orders
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Customer>(c => c.Orders); // Assuming 'Orders' is the navigation property
_db.LoadOptions = dlo;
var customersWithOrders = _db.Customers.ToList(); // Orders will be loaded here too
Summary
Querying data with LINQ to SQL offers a powerful and intuitive way to interact with your database. By leveraging LINQ, you can write concise, readable, and type-safe queries that are translated into efficient SQL statements.
This section covered:
- The role of the
DataContext
. - Basic querying operations: filtering, sorting, selecting.
- Joining and grouping data.
- Aggregation functions.
- Lazy vs. Eager loading.
Continue to the next section to explore data manipulation (inserting, updating, deleting) with LINQ to SQL.