ADO.NET Data Services и LINQ to SQL

Как правило работа сервисов ADO.NET Data Services представляется при использовании модели данных на основе ADO.NET Entity Framework. Однако, работа с реальными проектами (и заказчиками:)) порой диктует нам другие условия. Зачастую нет никакой необходимости использовать Entity Framework. И в этом случае мы задаемся вполне резонной задачей – использовать в качестве модели данных LINQ to SQL.

В ранних версиях ADO.NET Data Services все было просто — создаем модель данных, создаем сервис и все работает. С выходом релиза ADO.NET Data Services ситуация немного изменилась — при построении подобного сервиса на основе LINQ to SQL и обращении к этому сервису мы видим сообщение об ошибке.

Корни этой проблемы кроются в стратегии задания полей, содержащих первичные ключи. В ранних версиях при отсутствии явного указания этих полей инфраструктура ADO.NET Data Services сама пыталась определить их. Однако, в релизе эту стратегию поменяли и сейчас необходимо делать это явно.

Подобные поля задаются простым и естественным образом – путем навешивания атрибута DataServiceKey на сущность, в конструкторе которого как раз и указываются поля, являющиеся ключевыми. Информация о ключевых полях очень важна для сервиса, т.к. как вы помните при обращении к каждой конкретной сущности мы как раз указываем значение этого поля.

В чем же, собственно, проблема в LINQ to SQL? Проблема простая – LINQ to SQL при генерации сущности не помечает сущности этими атрибутами. Конечно же, это может вызвать негодование у разработчика, тем не менее этот досадный недостаток очень легко поправить. Вспомним, что все сущности в модели данных LINQ to SQL – это partial-классы. Сгенерируем partial-класс для каждой сущности модели данных и пометим атрибутом DataServiceKey эту сущность.

[DataServiceKey("NewsId")]
 partial class New
{

}

И вот, теперь наш сервис на базе LINQ to SQL работает.

На самом деле, существует некое соглашение, по которому ADO.NET Data Services пытается самостоятельно определить ключевые поля в сущности. Это соглашение заключается в следующем — если сущность не помечена атрибутом DataServiceKey, то выполняются следующие действия:

  1. Среди свойств сущности ищется поле ID. Если оно существует, то оно и будет являться ключевым;
  2. Если свойство ID не найдено, то ищется поле EntityTypeID, где EntityType – имя вашей сущности. Например, если ваша сущность называется Customer, то будет произведена попытка обнаружить свойство CustomerID. Если такой свойство найдено, то оно и будет ключевым.
  3. Если эти свойства не найдены, то будет сгенерирована ошибка.

Отдельное спасибо Phani Raj, за информацию о данном поведении.