Pergunta

Eu tenho uma classe base abstrata para propriedades de auditoria. Para a brevidade, diga que tem uma propriedade

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

E então meus objetos de domínio auditável herdam desta classe

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

Eu tenho a tabela seguinte DDL para a qual quero mapear meu objeto de domínio "fonte". Essencialmente, a relação entre cada objeto de domínio (concreto) e a tabela é 1-1, com cada tabela com a coluna de auditoria necessária.

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

Usando um arquivo de mapeamento externo, minha primeira tentativa de mapear a classe para a tabela seria tolamente:

<?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>

No entanto, isso gera a seguinte exceção:

A coluna ou associação 'CreatedTime' no mapeamento não possuía membro correspondente no tipo 'fonte'. Os membros do mapeamento do tipo de raiz acima não são suportados.

No contexto da minha camada de persistência, não estou tentando representar uma hierarquia de herança como tal, mas no contexto do meu aplicativo, estou simplesmente usando uma classe base para fornecer propriedades exigidas por todos os meus objetos de domínio. Com muitas mexendo com o meu arquivo de mapeamento (incluindo mapeamento das colunas de auditoria para o tipo de base abstrata e leitura de base) e leitura, não consigo conseguir o que considero uma tarefa ORM bastante reta.

Quaisquer pensamentos ou sugestões seriam bem -vindos! Obrigado

Foi útil?

Solução

Kelly mostrou uma ótima amostra de como fazê-lo-mas você basicamente atingiu uma das limitações do LINQ para SQL.

Funciona muito bem se o mapa da tabela de banco de dados mais ou menos 1: 1 nos seus objetos de domínio. Mas é fraco e causa muito trabalho extra quando esse não é mais o caso.

Nesse caso, assim que você tiver herança de objetos de domínio e outras coisas que precisam ser mapeadas para tabelas de banco de dados, sua melhor aposta seria verificar a estrutura da entidade ADO.NET. A EF é projetada especificamente para lidar com essas coisas - se você pensa "eu preciso mapa Meus objetos ...... "Então você deve pensar ef! :-)

É verdade que o envio atual da EF no .NET 3.5 SP1 tem suas verrugas e aborrecimentos, mas o EF 4 que faz parte da onda .NET 4.0 (que deve ser enviada antes do final deste ano de 2009) deve resolver muitos deles Verrugas!

Confira o Blog da equipe da estrutura da entidade ADO.NET Para alguns teasers do que o EF4 trará a todos nós!

Marc

Outras dicas

Acho que você está tentando imitar campos de auditoria como Ruby on Rails updated_on, created_on. Nesse caso, aqui está como eu realizei algo semelhante usando este post como ponto de partidahttp://weblogs.asp.net/stevesheldon/archive/2008/02/23/a-method-to-handle-audit-fields-using-linq-to-sql.aspx

Eu implementei uma interface no espaço de nome dos modelos como assim:

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

E depois estendeu as classes parciais das entidades de dados que tinham esses campos:

public partial class DataModelIWantToAudit : IAuditable
{
}

E depois substituiu SubmitChanges no DataContext Para verificar a implementação da interface com a magia de 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);
}

Espero que ajude! -Kelly

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top