Отображение производного класса в таблицу в Linq-to-SQL

У меня есть абстрактный базовый класс для свойств аудита. Для краткости скажу, что у него есть одно свойство

Public MustInherit Class AbstractAuditableEntity  
  ...  
  Public Property CreatedTime() As DateTimeOffset 
  ...
End Class  

И тогда мои проверяемые доменные объекты наследуются от этого класса

Public Class Source  
  Inherits AbstractAuditableEntity  
  ...        
  Public Property SourceId() As String  
  ...
End Class  

У меня есть следующая таблица DDL, с которой я хочу сопоставить свой объект домена "Источник". По сути, отношение между каждым (конкретным) объектом домена и таблицей составляет 1-1, причем каждая таблица имеет необходимый столбец аудита.

CREATE TABLE Source  
(  
   SourceID VARCHAR(10) NOT NULL,   
   CreatedTime   DATETIMEOFFSET(3) NOT NULL,  
   CONSTRAINT PK_Source PRIMARY KEY (SourceID))  
GO

Используя внешний файл сопоставления, моя первая попытка сопоставить класс с таблицей была бы глупой:

<?xml version="1.0" encoding="utf-8"?>
<Database Name="" xmlns="http://schemas.microsoft.com/linqtosql/mapping/2007">
  <Table Name="Source" Member="Sources">
    <Type Name ="Source">
      <Column Name="SourceID" Member="SourceID" IsPrimaryKey="true" CanBeNull="false"/>
      <Column Name="CreatedTime" Member="CreatedTime" />      
    </Type>
  </Table>
</Database>

Однако это создает следующее исключение:

Столбец или ассоциация "CreatedTime" в отображении не имели соответствующего члена в типе "Source". Отображение членов сверху корневого типа не поддерживается.

В контексте моего уровня персистентности я не пытаюсь представить иерархию наследования как таковую, но в контексте моего приложения я просто использую базовый класс для обеспечения свойств, требуемых всеми объектами моего домена. Из-за большого количества возни с моим файлом сопоставления (включая сопоставление столбцов аудита с базовым типом AbstractAuditableEntity) и чтения вокруг, я не могу достичь того, что я воспринимаю как довольно простую задачу ORM.

Любые мысли или предложения будут приветствоваться! Спасибо

2 ответа

Решение

Келли показал отличный пример того, как это сделать, но вы в основном столкнулись с одним из ограничений Linq-to-SQL.

Это прекрасно работает, если ваша таблица базы данных более или менее соответствует 1:1 объектам вашего домена. Но он слабый и требует много дополнительной работы, если это уже не так.

В таком случае, как только у вас появится наследование объекта домена и другие вещи, которые необходимо сопоставить с таблицами базы данных, лучше всего вместо этого проверить ADO.NET Entity Framework. EF специально разработан для того, чтобы справляться с этими вещами - если вы когда-нибудь думаете "мне нужно нанести на карту мои объекты…", тогда вам следует подумать о EF!:-)

Конечно, текущая поставка EF в.NET 3.5 SP1 имеет свои плюсы и неприятности, но EF 4, являющийся частью волны.NET 4.0 (которая должна появиться до конца 2009 года), должен решить многие из них. бородавки!

Загляните в блог команды ADO.NET Entity Framework, чтобы узнать, что принесет нам EF4!

Марк

Я предполагаю, что вы пытаетесь эмулировать поля аудита, такие как Ruby on Rails updated_on, created_on, Если так, то вот как я сделал нечто подобное, используя этот пост в качестве отправной точки http://weblogs.asp.net/stevesheldon/archive/2008/02/23/a-method-to-handle-audit-fields-using-linq-to-sql.aspx

Я реализовал интерфейс в пространстве имен Models следующим образом:

public interface IAuditable
{
    DateTime CreatedOn { get; set; }
    string CreatedBy { get; set; }
    DateTime? ChangedOn { get; set; }
    string ChangedBy { get; set; }
}

А затем расширили частичные классы объектов данных, которые имели эти поля:

public partial class DataModelIWantToAudit : IAuditable
{
}

А потом перебор SubmitChanges на DataContext проверить реализацию интерфейса с помощью магии Linq OfType<>:

public override void SubmitChanges(ConflictMode failureMode)
{         
    //Updates
    foreach (var updatedModel in GetChangeSet().Updates.OfType<IAuditable>())
    {
        updatedModel.ChangedOn = DateTime.Now;
        updatedModel.ChangedBy = Membership.GetUser().UserName;
    }

    //Inserts
    foreach (var insertedModel in GetChangeSet().Inserts.OfType<IAuditable>())
    {
        insertedModel.CreatedOn = DateTime.Now;
        insertedModel.CreatedBy = Membership.GetUser().UserName;
    }

    base.SubmitChanges(failureMode);
}

Надеюсь, это поможет! -Kelly

Другие вопросы по тегам