Часто задаваемые вопросы о LINQ - часть вторая
ОГЛАВЛЕНИЕ
- Скачать исходный код один-ко-многим и многие-к-одному - 1.02 MB
- Скачать LINQ-код оптимизированный при помощи DataLoadOption - 14.8 KB
- Скачать исходный код CRUD LINQ - 2.14 MB
- Скачать код хранимой процедуры - 1.06 MB
Введение и цель
Эта статья вопросов-ответов посвящена LINQ для SQL. Показан простой пример LINQ для SQL, как определить отношение 1-1 и 1-много с помощью LINQ, как можно оптимизировать запросы LINQ, выполнение хранимых процедур с помощью LINQ и простой пример создания, чтения, обновления, удаления (CRUD) с помощью LINQ для SQL.
Простой пример LINQ для SQL
Начнем с простого примера LINQ для SQL, а затем узнаем, как устанавливается отношение в сущностях LINQ.
Шаг 1: Определяются классы-сущности с помощью LINQ
При разработке проекта с помощью многоуровневого подхода, например, 3-уровневого или N-уровневого, приходится создавать бизнес-классы и объекты. Например, ниже показан простой класс, определяющий класс, сопоставленный с таблицей стран, как показано ниже. Свойства класса взаимно-однозначно сопоставлены с таблицей. Такие типы классов именуются классы-сущности.
В LINQ необходимо сначала определить эти классы-сущности с помощью сопоставлений атрибутов. Надо импортировать пространство имен “System.Data.Linq.Mapping;”, чтобы получить атрибуты для сопоставления. Ниже приведен фрагмент кода, показывающий, как атрибут ‘Таблица’ сопоставляет класс с таблицей базы данных по имени ‘Клиент’, и как атрибут ‘Столбец’ сопоставляет свойства со столбцами таблицы.
[Table(Name = "Customer")]
public class clsCustomerEntityWithProperties
{
private int _CustomerId;
private string _CustomerCode;
private string _CustomerName;
[Column(DbType = "nvarchar(50)")]
public string CustomerCode
{
set
{
_CustomerCode = value;
}
get
{
return _CustomerCode;
}
}
[Column(DbType = "nvarchar(50)")]
public string CustomerName
{
set
{
_CustomerName = value;
}
get
{
return _CustomerName;
}
}
[Column(DbType = "int", IsPrimaryKey = true)]
public int CustomerId
{
set
{
_CustomerId = value;
}
get
{
return _CustomerId;
}
}
}
Ниже дано более сложное наглядное изображение сопоставления классов-сущностей со структурой таблицы клиент.
Шаг 2: Используется datacontext для связывания данных таблицы с объектами-сущностями.
Второй шаг – использовать объект контекста данных LINQ для заполнения объектов-сущностей. Datacontext служит посредником между объектами базы данных и классами, сопоставленными с сущностями LINQ.
Создается объект datacontext и создается активное подключение с помощью строки подключения SQL.
DataContext objContext = new DataContext(strConnectionString);
Извлекается коллекция сущностей с помощью типа данных таблица. Это делается с помощью функции ‘gettable’ контекста данных.
Table<clsCustomerEntity> objTable =
objContext.GetTable<clsCustomerEntity>();
После извлечения всех данных в коллекции таблицы пора просмотреть коллекцию таблицы и отобразить запись.
foreach (clsCustomerEntity objCustomer in objTable)
{
Response.Write(objCustomer.CustomerName + "<br>");
}
Вышеприведенный исходный код приложен к статье.
Можно ли инкапсулировать свойства установки и извлечения для сущностей LINQ?
В предыдущем вопросе свойства класса-сущности предоставлялись как открытые свойства, что нарушало основное правило инкапсуляции. Можно определить функции сеттер (установщик) и геттер (извлекатель), инкапсулирующие закрытые свойства.
[Table(Name = "Customer")]
public class clsCustomerEntityWithProperties
{
private int _CustomerId;
private string _CustomerCode;
private string _CustomerName;
[Column(DbType = "nvarchar(50)")]
public string CustomerCode
{
set
{
_CustomerCode = value;
}
get
{
return _CustomerCode;
}
}
[Column(DbType = "nvarchar(50)")]
public string CustomerName
{
set
{
_CustomerName = value;
}
get
{
return _CustomerName;
}
}
[Column(DbType = "int", IsPrimaryKey = true)]
public int CustomerId
{
set
{
_CustomerId = value;
}
get
{
return _CustomerId;
}
}
}
Простой пример отношений 1-1 и 1-много.
LINQ помогает определять отношения с помощью ‘EntitySet’ и ‘EntityRef’. Чтобы понять, как определяются отношения с помощью LINQ, рассмотрим пример ниже, где имеется клиент, имеющий много адресов, а каждый адрес имеет номер телефона. То есть клиент и адрес имеют отношение один-к-многим, тогда как адрес и номер телефона имеют отношение один-к-одному.
Чтобы определить отношение один-к-многим между классами клиента и адреса, надо использовать атрибут ‘EntitySet’. Чтобы определить отношение один-к-одному между классами адреса и телефона, надо использовать атрибут ‘EntityRef’.
Замечание: Надо определить атрибут первичного ключа для каждого класса-сущности, иначе отношение сопоставления не будет работать.
Ниже приведен фрагмент сущности класса для класса клиента, показывающий, как используется ‘EntitySet’ для определения отношения один-к-многим с классом адреса. Ассоциация определяется с помощью атрибута ‘Association’. Атрибут ‘Association’ имеет три важных свойства: storage, thiskey и otherkey. ‘storage’ определяет имя закрытой переменной, где хранится объект адреса, сейчас это ‘_CustomerAddresses’. ‘ThisKey’ и ‘OtherKey’ определяют, какое свойство определяет связь, в данном примере это ‘CustomerId’. То есть класс ‘Customer’ и класс ‘Address’ имеют общее свойство ‘CustomerId’. ’ThisKey’ определяет имя свойства для класса клиента, тогда как ‘OtherKey’ определяет свойство класса адреса.
[Table(Name = "Customer")]
public class clsCustomerWithAddresses
{
private EntitySet<clsAddresses> _CustomerAddresses;
[Association(Storage = "_CustomerAddresses",ThisKey="CustomerId", OtherKey = "CustomerId")]
public EntitySet<clsAddresses> Addresses
{
set
{
_CustomerAddresses = value;
}
get
{
return _CustomerAddresses;
}
}
}
Ниже дан полный фрагмент кода с другими свойствами класса клиента.
[Table(Name = "Customer")]
public class clsCustomerWithAddresses
{
private int _CustomerId;
private string _CustomerCode;
private string _CustomerName;
private EntitySet<clsAddresses> _CustomerAddresses;
[Column(DbType="int",IsPrimaryKey=true)]
public int CustomerId
{
set
{
_CustomerId = value;
}
get
{
return _CustomerId;
}
}
[Column(DbType = "nvarchar(50)")]
public string CustomerCode
{
set
{
_CustomerCode = value;
}
get
{
return _CustomerCode;
}
}
[Column(DbType = "nvarchar(50)")]
public string CustomerName
{
set
{
_CustomerName = value;
}
get
{
return _CustomerName;
}
}
[Association(Storage = "_CustomerAddresses",ThisKey="CustomerId", OtherKey = "CustomerId")]
public EntitySet<clsAddresses> Addresses
{
set
{
_CustomerAddresses = value;
}
get
{
return _CustomerAddresses;
}
}
}
Чтобы определить отношение между классом адреса и классом телефона, надо использовать синтаксис ‘EntityRef’. Ниже приведен фрагмент кода, определяющий отношение с помощью ‘EntityRef’. Все остальные свойства такие же, кроме того, что переменная определяется с помощью ‘EntityRef’.
public class clsAddresses
{
private int _AddressId;
private EntityRef<clsPhone> _Phone;
[Column(DbType = "int", IsPrimaryKey = true)]
public int AddressId
{
set
{
_AddressId = value;
}
get
{
return _AddressId;
}
}
[Association(Storage = "_Phone",
ThisKey = "AddressId", OtherKey = "AddressId")]
public clsPhone Phone
{
set
{
_Phone.Entity = value;
}
get
{
return _Phone.Entity;
}
}
}
Ниже приведен полный класс адреса с остальными свойствами.
public class clsAddresses
{
private int _Customerid;
private int _AddressId;
private string _Address1;
private EntityRef<clsPhone> _Phone;
[Column(DbType="int")]
public int CustomerId
{
set
{
_Customerid = value;
}
get
{
return _Customerid;
}
}
[Column(DbType = "int", IsPrimaryKey = true)]
public int AddressId
{
set
{
_AddressId = value;
}
get
{
return _AddressId;
}
}
[Column(DbType = "nvarchar(50)")]
public string Address1
{
set
{
_Address1 = value;
}
get
{
return _Address1;
}
}
[Association(Storage = "_Phone",
ThisKey = "AddressId", OtherKey = "AddressId")]
public clsPhone Phone
{
set
{
_Phone.Entity = value;
}
get
{
return _Phone.Entity;
}
}
}
Класс телефона, объединенный с классом адреса.
[Table(Name = "Phone")]
public class clsPhone
{
private int _PhoneId;
private int _AddressId;
private string _MobilePhone;
private string _LandLine;
[Column(DbType = "int", IsPrimaryKey = true)]
public int PhoneId
{
set
{
_PhoneId = value;
}
get
{
return _PhoneId;
}
}
[Column(DbType = "int")]
public int AddressId
{
set
{
_PhoneId = value;
}
get
{
return _PhoneId;
}
}
[Column(DbType = "nvarchar")]
public string MobilePhone
{
set
{
_MobilePhone = value;
}
get
{
return _MobilePhone;
}
}
[Column(DbType = "nvarchar")]
public string LandLine
{
set
{
_LandLine = value;
}
get
{
return _LandLine;
}
}
}
Теперь надо использовать это отношение в выделенном коде клиента ASPX.
Первый шаг - создать объект контекста данных с инициализированным подключением.
DataContext objContext = new DataContext(strConnectionString);
Второй шаг – запустить запрос. Только запускается запрос для класса клиента. Механизм LINQ следит за тем, чтобы все данные дочерних таблиц были извлечены и размещены согласно отношению, определенному в классах-сущностях.
var MyQuery = from objCustomer in objContext.GetTable<clsCustomerWithAddresses>()
select objCustomer;
Наконец, проходим в цикле по клиентам, проходим в цикле по соответствующему объекту адресов и выводим на экран номер телефона согласно объекту телефона.
foreach (clsCustomerWithAddresses objCustomer in MyQuery)
{
Response.Write(objCustomer.CustomerName + "<br>");
foreach (clsAddresses objAddress in objCustomer.Addresses)
{
Response.Write("===Address:- " + objAddress.Address1 + "<br>");
Response.Write("========Mobile:- " + objAddress.Phone.MobilePhone + "<br>");
Response.Write("========LandLine:- " + objAddress.Phone.LandLine + "<br>");
}
}
Вывод выглядит так, как показано ниже. Каждый клиент имеет несколько адресов, и каждый адрес имеет объект телефона.
Как происходят полные обходы в LINQ
Сначала разберем, как на самом деле работают запросы LINQ, а затем узнаем, как происходят полные обходы. Рассмотрим следующую структуру базы данных с 3 таблицами – customer(клиент), addresses(адреса) и phone(телефон). Есть отношение один-к-многим между клиентом и адресами, а между таблицами адресов и телефонов есть отношение один-к-одному.
Были созданы три сущности согласно структуре таблицы, т.е. ‘ClsCustomerWithAddresses’,’ClsAddresses’ и ‘ClsPhone’. Были определены отношения между ними с помощью ‘EntitySet’ и ‘EntityRef’.
Заполнение объектов-сущностей данными из таблицы – процесс из 5 шагов. На первом шаге создается подключение datacontext с помощью строки подключения, создается запрос LINQ, а затем начинается просмотр клиента, адреса и телефонов.
Анализ полных обходов LINQ SQL
Было разобрано 5 шагов выполнения запроса LINQ. Выясним, на каком шаге запрос LINQ фактически запускает SQL в базе данных. Запустим вышеуказанный код LINQ и проанализируем его с помощью профилировщика SQL.
Чтобы не поймать кучу шума сервера SQL, были включены только групповые события RPC и SQL.
Теперь при выполнении запроса выясняется следующее:
• Выполнение реального SQL происходит, когда инструкция foreach повторяется над объектами LINQ.
• Для каждой сущности запускается отдельный запрос к серверу SQL. Например, запускается один запрос для клиента, и затем запускаются отдельные запросы для адреса и телефонов, чтобы вырастить объект сущности. То есть много полных обходов.
Как избежать лишних полных обходов
Можно приказать механизму LINQ загружать все объекты с помощью ‘DataLoadOptions’. Ниже описаны шаги по включению ‘DataLoadOptions’.
Первый шаг – создать класс контекста данных.
DataContext objContext = new DataContext(strConnectionString);
Второй шаг – создать объект ‘DataLoadOption’.
DataLoadOptions objDataLoadOption = new DataLoadOptions();
С помощью метода LoadWith надо определить загрузку клиента с адресом в одном SQL.
objDataLoadOption.LoadWith<clsCustomerWithAddresses>(clsCustomerWithAddresses => clsCustomerWithAddresses.Addresses);
Каждый объект адреса имеет объект телефона, поэтому была определена опция, говорящая, что объекты телефона должны загружаться для каждого объекта адреса в одном SQL.
objDataLoadOption.LoadWith<clsAddresses>(clsAddresses => clsAddresses.Phone);
Какая бы опция загрузки ни была определена, надо установить то же самое в объекте контекста данных с помощью свойства ‘LoadOptions’.
objContext.LoadOptions = objDataLoadOption;
Наконец, готовится запрос.
var MyQuery = from objCustomer in objContext.GetTable<clsCustomerWithAddresses>()
select objCustomer;
Начинается обход объектов в цикле.
foreach (clsCustomerWithAddresses objCustomer in MyQuery)
{
Response.Write(objCustomer.CustomerName + "<br>");
foreach (clsAddresses objAddress in objCustomer.Addresses)
{
Response.Write("===Address:- " + objAddress.Address1 + "<br>");
Response.Write("========Mobile:- " + objAddress.Phone.MobilePhone + "<br>");
Response.Write("========LandLine:- " + objAddress.Phone.LandLine + "<br>");
}
}
Ниже приведен полный исходный код для того же самого.
DataContext objContext = new DataContext(strConnectionString);
DataLoadOptions objDataLoadOption = new DataLoadOptions();
objDataLoadOption.LoadWith<clsCustomerWithAddresses>(clsCustomerWithAddresses => clsCustomerWithAddresses.Addresses);
objDataLoadOption.LoadWith<clsAddresses>(clsAddresses => clsAddresses.Phone);
objContext.LoadOptions = objDataLoadOption;
var MyQuery = from objCustomer in objContext.GetTable<clsCustomerWithAddresses>()
select objCustomer;
foreach (clsCustomerWithAddresses objCustomer in MyQuery)
{
Response.Write(objCustomer.CustomerName + "<br>");
foreach (clsAddresses objAddress in objCustomer.Addresses)
{
Response.Write("===Address:- " + objAddress.Address1 + "<br>");
Response.Write("========Mobile:- " + objAddress.Phone.MobilePhone + "<br>");
Response.Write("========LandLine:- " + objAddress.Phone.LandLine + "<br>");
}
}
Теперь при запуске кода LINQ выполняет только один SQL с должными соединениями по сравнению с 3 SQL для каждого объекта, показанными ранее.
Исходный код
К данной статье был приложен исходный код. Запустите проект и посмотрите, как профилировщик показывает разное выполнение SQL. Сначала запустите пример ‘EntitySet’ и посмотрите, как профилировщик SQL реагирует на то же самое, а затем запустите пример с ‘DataLoadOptions’. Скрипт SQL приложен в отдельном файле.
Как выполняются хранимые процедуры с помощью LINQ
Шаг 1: Создать хранимую процедуру
Ниже приведена хранимая процедура, используемая для выращивания объектов LINQ.
Create PROCEDURE dbo.usp_SelectCustomer
AS
Select CustomerId,CustomerCode,CustomerName from Customer
RETURN
Шаг 2: Создать сущность LINQ
Вышеуказанная хранимая процедура возвращает ‘CustomerId’,’CustomerCode’ и ‘CustomerName’, поэтому надо приготовить сущность LINQ согласно данным, возвращаемым хранимой процедурой. Если вы не знакомы с сущностями LINQ, прочитайте основы в OneManyandOneOneLINQ.aspx
[Table(Name = "Customer")]
public class clsCustomerEntity
{
private int _CustomerId;
private string _CustomerCode;
private string _CustomerName;
[Column(DbType = "nvarchar(50)")]
public string CustomerCode
{
set
{
_CustomerCode = value;
}
get
{
return _CustomerCode;
}
}
[Column(DbType = "nvarchar(50)")]
public string CustomerName
{
set
{
_CustomerName = value;
}
get
{
return _CustomerName;
}
}
[Column(DbType = "int", IsPrimaryKey = true)]
public int CustomerId
{
set
{
_CustomerId = value;
}
get
{
return _CustomerId;
}
}
}
Шаг 3: Унаследовать от класса DataContext
Для выполнения хранимых процедур LINQ предоставляет функцию вызова ‘ExecuteMethod’, принадлежащую классу ‘DataContext’. Эта функция возвращает ‘ISingleresult’ коллекции сущностей. Функция вызова ‘ExecuteMethod’ – защищенная функция и вызывается только через наследование. Методы и функции, из которых вызываются хранимые процедуры, формируют DAL. То есть ‘ExecuteMethod’ должен входить в DAL.
Как сказано, функция чисто защищенная, вызываемая только путем наследования, а не агрегирования. Неясно, почему Microsoft принуждает к этому, поэтому надо создать еще один лишний класс, наследуемый от ‘DataContext’, а затем вставить соответствующие вызовы функции для хранимых процедур. Ниже приведен фрагмент кода, в котором наследуется от класса ‘DataContext’ и создается новый класс DAL по имени ‘ClsMyContext’.
public class clsMyContext : DataContext
{}
Шаг 4: Приписать с помощью атрибута Функция
Была создана функция ‘GetCustomerAll’, приписанная с помощью атрибута ‘Function’ из пространства имен ‘System.Data.Linq.Mapping’. Атрибут ‘Function’ имеет параметр имя, задающий имя хранимой процедуры; сейчас хранимая процедура - ‘usp_SelectCustomer’, как определено в предыдущих шагах.
Параметр ‘IsComposable’ определяет, предназначен ли этот вызов метода (для или) для UDF, т.е. определённой пользователем функции. Если ‘IsComposable’ равен false, то это хранимая процедура, а если равен true, то это определённая пользователем функция.
[Function(Name = "usp_SelectCustomer", IsComposable = false)]
public ISingleResult<clsCustomerEntity> getCustomerAll()
{
}
Шаг 5: Вызвать вызов Executemethod
Пора заполнить пустую функцию ‘GetCustomerAll’. Ниже приведен фрагмент кода, выполняющий вызов ‘ExecuteMethod’. Этот вызов возвращает объект ‘IExecuteResult’.
IExecuteResult objResult = this.ExecuteMethodCall(this,(MethodInfo)(MethodInfo.GetCurrentMethod()));
Объект, возвращенный из ‘IExecuteResult’, имеет свойство ‘ReturnValue’, из которого можно получить коллекцию результатов типа ‘ClsCustomerEntity’.
ISingleResult<clsCustomerEntity> objresults = (ISingleResult<clsCustomerEntity>) objResult.ReturnValue;
Ниже приведен полный фрагмент кода с функцией.
[Function(Name = "usp_SelectCustomer", IsComposable = false)]
public ISingleResult<clsCustomerEntity> getCustomerAll()
{
IExecuteResult objResult = this.ExecuteMethodCall(this,(MethodInfo)(MethodInfo.GetCurrentMethod()));
ISingleResult<clsCustomerEntity> objresults = (ISingleResult<clsCustomerEntity>) objResult.ReturnValue;
return objresults;
}
Шаг 6: Вызвать контекст данных в клиенте
На последнем шаге создается объект контекста, вызывается функция, и коллекция объектов обходится в цикле с выводом данных на экран.
clsMyContext objContext = new clsMyContext(strConnectionString);
foreach(var row in objContext.getCustomerAll())
{
Response.Write(row.CustomerCode);
}
Объясните фиксацию в памяти и физическую фиксацию LINQ
Объекты-сущности образуют основу технологий LINQ. Поэтому при отправке любых данных в базу данных они проходят через объекты LINQ. Операции базы данных делаются посредством класса ‘DataContext’. Как сказано выше, сущности образуют основу LINQ, поэтому все данные сначала отправляются этим сущностям и затем направляются в реальную физическую базу данных. Из-за этого фиксация транзакции базы данных является двухэтапным процессом: первый этап происходит в памяти, а второй этап – физическая фиксация.
Для выполнения операции в памяти ‘DataContext’ предоставляет методы ‘DeleteOnSubmit’ и ‘InsertOnSubmit’. Когда эти методы вызываются из класса ‘DataContext’, они добавляют и обновляют данные в памяти объектов-сущностей. Учтите, что эти методы не меняют / не добавляют новые данные в реальную базу данных.
После завершения операций в памяти вызывается метод ‘SubmitChanges()’ для отправки всех обновлений в базу данных. Этот метод фиксирует данные в физической базе данных.
Рассмотрим таблицу пользователей (customerid, customercode и customername) и посмотрим, как делаются операции фиксации в памяти и физической фиксации.
Простой пример CRUD с помощью LINQ
Шаг 1: Создать сущность класса «Клиент»
На первом шаге создается сущность класса «Клиент», как показано в следующем фрагменте кода.
[Table(Name = "Customer")]
public class clsCustomerEntity
{
private int _CustomerId;
private string _CustomerCode;
private string _CustomerName;
[Column(DbType = "nvarchar(50)")]
public string CustomerCode
{
set
{
_CustomerCode = value;
}
get
{
return _CustomerCode;
}
}
[Column(DbType = "nvarchar(50)")]
public string CustomerName
{
set
{
_CustomerName = value;
}
get
{
return _CustomerName;
}
}
[Column(DbType = "int", IsPrimaryKey = true,IsDbGenerated=true)]
public int CustomerId
{
set
{
_CustomerId = value;
}
get
{
return _CustomerId;
}
}
}
Шаг 2: Создание (create) с помощью LINQ
Создать контекст данных
Сначала создается объект ‘datacontext’ с использованием строки подключения.
DataContext objContext = new DataContext(strConnectionString);
Установить данные для вставки
Следующий шаг после создания подключения с помощью объекта ‘DataContext’ – создать объект-сущность «Клиент» и присвоить данные свойству объекта.
clsCustomerEntity objCustomerData = new clsCustomerEntity();
objCustomerData.CustomerCode = txtCustomerCode.Text;
objCustomerData.CustomerName = txtCustomerName.Text;
Сделать обновление в памяти
Затем делается обновление в памяти в самих объектах-сущностях с помощью метода ‘InsertOnSubmit’.
objContext.GetTable<clsCustomerEntity>().InsertOnSubmit(objCustomerData);
Сделать конечную физическую фиксацию
Наконец, делается физическая фиксация в реальной базе данных. Помните, что пока не вызван ‘SubmitChanges()’, данные не зафиксированы окончательно в базе данных.
objContext.SubmitChanges();
Окончательный код
Ниже приведен окончательный собранный код LINQ.
DataContext objContext = new DataContext(strConnectionString);
clsCustomerEntity objCustomerData = new clsCustomerEntity();
objCustomerData.CustomerCode = txtCustomerCode.Text;
objCustomerData.CustomerName = txtCustomerName.Text;
objContext.GetTable<clsCustomerEntity>().InsertOnSubmit(objCustomerData);
objContext.SubmitChanges();
Шаг 3: Обновление (update) с помощью LINQ
Возьмем следующую операцию базы данных, т.е. «Обновить».
Создать контекст данных
Как обычно, сначала надо создать объект ‘datacontext’ с помощью строки подключения, как сказано в шаге «Создать».
DataContext objContext = new DataContext(strConnectionString);
Выбрать объект LINQ пользователь, который надо обновить
Получить путем запроса LINQ объект LINQ, который надо обновить
var MyQuery = from objCustomer in objContext.GetTable<clsCustomerEntity>()
where objCustomer.CustomerId == Convert.ToInt16(txtCustomerId.Text)
select objCustomer;
Наконец, установить новые значения и обновить данные в физической базе данных
Делаются обновления и вызывается ‘SubmitChanges()’ для осуществления окончательного обновления.
clsCustomerEntity objCustomerData = (clsCustomerEntity)MyQuery.First<clsCustomerEntity>();
objCustomerData.CustomerCode = txtCustomerCode.Text;
objCustomerData.CustomerName = txtCustomerName.Text;
objContext.SubmitChanges();
Окончательный код «Обновить на LINQ»
Ниже показано, как выглядит окончательный запрос на обновление на LINQ.
DataContext objContext = new DataContext(strConnectionString);
var MyQuery = from objCustomer in objContext.GetTable<clsCustomerEntity>()
where objCustomer.CustomerId == Convert.ToInt16(txtCustomerId.Text)
select objCustomer;
clsCustomerEntity objCustomerData = (clsCustomerEntity)MyQuery.First<clsCustomerEntity>();
objCustomerData.CustomerCode = txtCustomerCode.Text;
objCustomerData.CustomerName = txtCustomerName.Text;
objContext.SubmitChanges();
Шаг 4: Удаление (Delete) с помощью LINQ
Рассмотрим следующую операцию базы данных – «Удалить».
DeleteOnSubmit
Не разбираются предыдущие шаги, такие как создание контекста данных и выбор объекта LINQ, они объяснены в предыдущем разделе. Чтобы удалить объект из памяти, надо вызвать ‘DeleteOnSubmit()’, а для удаления из конечной базы данных надо использовать ‘SubmitChanges()’.
objContext.GetTable<clsCustomerEntity>().DeleteOnSubmit(objCustomerData);
objContext.SubmitChanges();
Шаг 5: Понятные без пояснений выборка (select) и чтение (read) на LINQ
На последнем шаге объект LINQ выбирается и читается по условию. Ниже приведен фрагмент кода, показывающий, как запустить запрос LINQ и присвоить значение объекта пользовательскому интерфейсу ASP.NET.
DataContext objContext = new DataContext(strConnectionString);
var MyQuery = from objCustomer in objContext.GetTable<clsCustomerEntity>()
where objCustomer.CustomerId == Convert.ToInt16(txtCustomerId.Text)
select objCustomer;
clsCustomerEntity objCustomerData = (clsCustomerEntity)MyQuery.First<clsCustomerEntity>();
txtCustomerCode.Text = objCustomerData.CustomerCode;
txtCustomerName.Text = objCustomerData.CustomerName;