2013-05-24 6 views
8

Я новичок в Entity Framework, в прошлом я использовал Enterprise Library или ADO.NET напрямую, чтобы сопоставлять модели с таблицами базы данных. Один шаблон, который я использовал, состоит в том, чтобы поместить мои общие поля аудита в каждую таблицу базового класса, а затем наследовать этот базовый класс для каждого объекта.Код структуры Entity Framework Первые общие поля аудита базы данных

Я два шага для защиты двух полей (Created, CreatedBy):

  1. Have без параметров конструктор приватным на базе Enitity и создать второй, который требует Created и CreatedBy передаются по созданию.
  2. Сделать сеттеры приватными, чтобы значения не могли быть изменены после создания объекта.

Базовый класс:

using System; 

namespace App.Model 
{ 
    [Serializable()] 
    public abstract class BaseEntity 
    { 
     public bool IsActive { get; private set; } 
     public DateTimeOffset Created { get; private set; } 
     public string CreatedBy { get; private set; } 
     public DateTimeOffset LastUpdated { get; protected set; } 
     public string LastUpdatedBy { get; protected set; } 

     private BaseEntity() { } 

     protected BaseEntity(DateTimeOffset created, string createdBy) 
     { 
      IsActive = true; 
      Created = created; 
      CreatedBy = createdBy; 
      LastUpdated = created; 
      LastUpdatedBy = createdBy; 
     } 
    } 
} 

Наследуется Класс:

using System; 

namespace App.Model 
{ 
    [Serializable()] 
    public class Person : BaseEntity 
    { 
     public int Id { get; set; } 
     public string FirstName { get; set; } 
     public string LastName { get; set; } 
     public string Email { get; set; } 

     public Person(DateTimeOffset created, string createdBy) : 
      base(created, createdBy) { } 
    } 
} 

Я столкнулся с проблемами с обоими. Для создания объектов EF требует конструктор без параметров. EF не будет создавать столбцы базы данных, у которых есть собственный сеттер.

Мой вопрос, если есть лучший подход для достижения своих целей с EF:

  1. Требуют, что значения для создания и CreatedBy заполняются в конкретизации.
  2. Значения Created и CreatedBy не могут быть изменены.
+2

Существует еще один вариант: переопределить 'SaveChanges' в вашем контексте и выполнять все связанные с аудитом действия (установить дату создания для новых объектов, установить дату изменения для обновленных объектов и т. Д.). Все это будет сделано перед сохранением. –

+0

[У меня была такая же проблема и я нашел это полезным.] (Http://jmdority.wordpress.com/2011/07/20/using-entity-framework-4-1-dbcontext-change-tracking-for-audit- logging /) –

+0

Вместо этого я бы реализовал интерфейс «IAuditiable», таким образом вы все еще можете иметь объекты, которые не должны быть проверены, и те, которые должны быть реализованы с помощью логики, специфичной для этого интерфейса в вашем вызове SaveChanges(), как это предлагается в одном из ответы ниже, если это то, что вы хотите. – FRoZeN

ответ

0

Вы не должны пытаться контролировать права доступа непосредственно на своих объектах/слоях данных, вместо этого вы должны делать это на своем прикладном уровне. Таким образом, у вас есть более тонкий уровень контроля над тем, что пользователи могут делать.

Кроме того, чтобы поля проверки повторялись на каждой таблице, вы можете захотеть сохранить свои записи аудита в другой таблице. Это легко сделать с кодом первым:

public class AuitRecord 
{ 
    public bool IsActive { get; set; } 
    public DateTimeOffset Created { get; set; } 
    public string CreatedBy { get; set; } 
    public DateTimeOffset LastUpdated { get; set; } 
    public string LastUpdatedBy { get; set; } 
} 

Вы бы затем связать базовый класс с записью аудита к нему:

public abstract class BaseEntity 
{ 
    public AuditRecord Audit { get; set; } 
} 

И, наконец, ваши фактически Entities

public class Person : BaseEntity 
{ 
    public int Id { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public string Email { get; set; } 
} 

You не может получить доступ к данным аудита путем:

Person.Audit.IsActive 
+0

Интересно, но это не соответствует цели, требующей, чтобы созданные и созданные элементы были заполнены при создании объекта. Кроме того, наличие отдельной таблицы аудита означает, что вам понадобится ключ (не показан в AuditClass), который мог бы ссылаться на любые другие ключи сущностей. Это не будет третьей нормальной формой. Другая проблема с общей аудиторской таблицей, с которой я столкнулся, - это проблема производительности, потому что она становится шеей бутылки для производительности. – Josh

+0

@Josh: Фактически вы можете оставаться в 3NF, добавляя ключ к классу AuditRecord и имея все остальные объекты, содержащие «Список » (что создало бы отношения «один ко многим» со всеми вашими проверенными объектами и аудитом Таблица). Это будет лишь узким местом для вставок и обновлений (которые должны быть оптимизированы так быстро, насколько это возможно), поэтому это может не быть проблемой в зависимости от ваших требований/реализации. –

5

Вы можете создать экземпляр контекста с помощью конструктора, который принимает строку createdBy.Тогда в переопределение SaveChanges():

public override int SaveChanges() 
{ 
    foreach(var entity in ChangeTracker.Entries() 
             .Where(e => e.State == EntityState.Added) 
             .Select (e => e.Entity) 
             .OfType<BaseEntity>()) 
    { 
     entity.SetAuditValues(DateTimeOffset.Now, this.CreatedBy); 
    } 
    return base.SaveChanges(); 
} 

С SetAuditValues() в

internal void SetAuditValues(DateTimeOffset created, string createdBy) 
{ 
    if (this.Created == DateTimeOffset.MinValue) this.Created = created; 
    if (string.IsNullOrEmpty(this.CreatedBy)) this.CreatedBy = createdBy; 
} 

После того, как объекты были материализовался из базы данных значения не будут перезаписаны когда кто-то называет SetAuditValues.

+0

Это выглядит близко, но у меня все еще есть проблема с тем, что столбцы не создаются, потому что сеттеры являются закрытыми. Я мог бы защитить их, но тогда кто-то мог просто вызвать Person.Created = new-value. Он не будет сохранен в базе данных из-за SetAuditValues, но это было бы недопустимым состоянием в памяти перед сохранением. – Josh

+0

Вы должны быть в состоянии добавить свойства к модели путем свободного отображения, не так ли? –

+0

Да и Нет - вам нужно использовать поле для чтения только для псевдонима, чтобы обойти проблему Private Setter с плавным отображением. Решение - это немного взлома. – Josh

Смежные вопросы