API-интерфейс System.Data.Linq

40

»» В ДАННОЙ СТАТЬЕ ИСПОЛЬЗУЕТСЯ ИСХОДНЫЙ КОД ДЛЯ ПРИМЕРОВ

В пространстве имен System.Data.Linq существует группа классов, которые будут регулярно применяться при использовании LINQ to SQL. В этой статье представлен краткий обзор этих классов, их свойств и места в схеме LINQ to SQL.

EntitySet<T>

Сущностный класс на стороне один в отношении "один ко многим" хранит ассоциированные с ним сущностные классы стороны многие в своем члене класса типа EntitySet<T>, где T — тип ассоциированного сущностного класса.

Поскольку в базе данных Northwind отношение между заказами и заказчиками построено по схеме "один ко многим", в классе Customer соответствующие ему Orders хранятся в EntitySet<Order>:

private EntitуSеt<Order> _Orders;

Класс EntitySet<T> представляет собой специальную коллекцию, используемую LINQ to SQL. Он реализует интерфейс IEnumerable<T>, который позволяет выполнять на нем запросы LINQ. Кроме того, он реализует интерфейс ICollection<T>.

EntityRef<T>

Сущностный класс на стороне многие отношения "один ко многим" хранит ассоциированный с ним класс стороны один в члене типа EntityRef<T>, где T — тип ассоциированного сущностного класса.

Поскольку в базе данных Northwind отношение между заказами и заказчиками построено по схеме "один ко многим", класс Customer сохраняется в классе Order в члене типа EntityRef<Customer>:

private EntityRef<Customer> _Customer;

Entity

Когда мы ссылаемся на ассоциированный сущностный класс, представляющий сторону один в отношении "один ко многим", то склонны думать, что соответствующая переменная-член имеет тот же тип, что и сущностный класс.

Например, когда мы ссылаемся на Customer объекта Order, то думаем, что объект Customer хранится в члене класса Order типа Customer. Однако на самом деле следует помнить, что Customer хранится в EntityRef<Customer>. Когда нужно обратиться к действительной ссылке на объект Customer из члена типа EntityRef<Customer>, это должно делаться через член объекта EntityRef<Customer> по имени Entity.

Бывают случаи, когда важно осознавать этот факт — например, при написании собственных сущностных классов. Если вы взглянете на класс Order, сгенерированный SQLMetal, то заметите, что общедоступные методы get и set свойства Customer используют свойство Entity объекта EntityRef<Customer>, чтобы обратиться к Customer:

private EntityRef _Customer;
...                  

public Customer Customer
		{
			get
			{
				return this._Customer.Entity;
			}
			set
			{
				Customer previousValue = this._Customer.Entity;
				...
			}                  

HasLoadedOrAssignedValue

Это булевское свойство позволяет узнать, присвоено ли свойству класса, хранящемуся в EntityRef<T>, значение, или же оно было загружено в него.

Обычно оно используется в методах set для ссылок на сторону один в ассоциации "один ко многим", чтобы предотвратить несогласованность между свойством класса, хранящим идентификаторы стороны один, и EntityRef <Т>, хранящим ссылку на сторону один.

Например, давайте посмотрим на методы set для свойствa CustomerID сущностного класса Order:

public string CustomerID
		{
			get
			{
				return this._CustomerID;
			}
			set
			{
				if ((this._CustomerID != value))
				{
					if (this._Customer.HasLoadedOrAssignedValue)
					{
						throw new System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException();
					}
					this.OnCustomerIDChanging(value);
					this.SendPropertyChanging();
					this._CustomerID = value;
					this.SendPropertyChanged("CustomerID");
					this.OnCustomerIDChanged();
				}
			}
		}

Обратите внимание в методе set для свойства CustomerID, что если EntityRef<T>, хранящий Customer, имеет свойство HasLoadedOrAssignedValue, равное true, то генерируется исключение. Это предохраняет разработчика от изменения CustomerID сущностного объекта Order, если этот Order уже имеет присвоенную ему сущность Customer. Благодаря такой защите, даже при желании невозможно достичь рассогласованности между CustomerID и Customer сущностного объекта Order.

В отличие от этого, в методе set для свойства Customer ссылка Customer может быть присвоена, только если свойство HasLoadedOrAssignedValue установлено в false.

Проверка значения свойства HasLoadedOrAssignedValue в каждом методе set предохраняет разработчика от внесения несогласованности между ссылками CustomerID и Customer.

Table<Т>

Этот тип данных LINQ to SQL использует для взаимодействия с таблицей или представлением в базе данных SQL Server. Обычно производный от DataContext класс, который часто назывался [Your]DataContext, будет иметь общедоступное свойство типа Table<Т>, где T — сущностный класс, для каждой таблицы базы данных в наследнике DataContext. Он должен выглядеть примерно так, как показано ниже:

public System.Data.Linq.Table<Customer> Customers
{
   get
   {
      return this.GetTable<Customer>();
   }
}

Table<T> реализует интерфейс IQueryable<T>, который сам реализует IEnumerable<T>. Это значит, что на нем можно выполнять запросы LINQ to SQL. Это — начальный источник данных для большинства запросов LINQ to SQL.

IExecuteResult

Когда методом ExecuteMethodCall вызывается хранимая процедура или определяемая пользователем функция, то результаты возвращаются в объекте, реализующем интерфейс IExecuteResult, как показано ниже:

IExecuteResult result = this.ExecuteMethodCall(...);

Интерфейс IExecuteResult предоставляет одно свойство по имени ReturnValue и один метод по имени GetParametrValue для доступа к возвращенному значению и выходному параметру соответственно.

ReturnValue

Все результаты хранимой процедуры, кроме выходных параметров и результатов функций, определяемых пользователем, возвращаются через переменную IExecuteResult.ReturnValue.

Чтобы получить доступ к возвращенному значению хранимой процедуры или функции со скалярным типом возврата, вы oбращаетесь к члену ReturnValue возвращенного объекта. Ваш код должен выглядеть примерно так, как показано ниже:

IExecuteResult result = this.ExecuteMethodCall(...); 
int returnCode = (int)(result.ReturnValue);

Если хранимая процедура возвращает данные помимо ее возвращенного значения, то переменная ReturnValue будет реализовывать интерфейс ISingleResult<T> или IMultipleResults, который больше подходит, в зависимости от того, сколько форм данных возвращается из хранимой процедуры.

GetParametrValue

Для получения доступа к выходным параметрам хранимой процедуры на возвращенном объекте вызывается метод GetParameterValue с передачей ему начинающегося с нуля индекса параметра, значение которого требуется получить. Если предположить, что хранимая процедура возвращает CompanyName в третьем параметре, то код может выглядеть примерно так, как показано ниже:

IExecuteResult result = this.ExecuteMethodCall(..., param1, param2, companyName);
string CompanyName = (string)(result.GetParameterValue(2));
Пройди тесты
Лучший чат для C# программистов