2013-05-24 38 views
8

Tôi mới dùng Entity Framework, trước đây tôi đã sử dụng Enterprise Library hoặc ADO.NET trực tiếp để ánh xạ các mô hình tới các bảng cơ sở dữ liệu. Một mẫu mà tôi đã sử dụng là đặt các trường kiểm toán chung của tôi xuất hiện trong mỗi bảng trong một Lớp cơ sở và sau đó kế thừa Lớp cơ sở đó cho mọi đối tượng.Mã khung thực thể Cơ sở dữ liệu chung đầu tiên

Tôi mất hai bước để bảo vệ hai trong số các lĩnh vực (Created, CreatedBy):

  1. Có một tin constructor parameterless trên Enitity cơ sở và tạo một thứ hai mà đòi hỏi phải tạo và CreatedBy được thông qua vào sáng tạo.
  2. Đặt bộ cài đặt Riêng tư để không thể thay đổi các giá trị sau khi đối tượng được tạo.

Base Class:

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; 
     } 
    } 
} 

Kế thừa Class:

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) { } 
    } 
} 

tôi đã chạy vào các vấn đề với cả hai. EF yêu cầu một hàm tạo tham số để tạo các đối tượng. EF sẽ không tạo ra các cột cơ sở dữ liệu có trình thiết lập riêng.

Câu hỏi của tôi là nếu có một cách tiếp cận tốt hơn để hoàn thành mục tiêu của tôi với EF:

  1. Yêu cầu các giá trị cho Created và CreatedBy được dân cư tại instantiation.
  2. Không thể thay đổi giá trị của Tạo và TạoBởi.
+2

Có một tùy chọn khác: ghi đè 'SaveChanges' trong ngữ cảnh của bạn và thực hiện tất cả các hành động liên quan đến kiểm toán tại đó (thiết lập ngày tạo trên thực thể mới, thiết lập ngày sửa đổi trên thực thể được cập nhật v.v.). Tất cả sẽ được thực hiện ngay trước khi lưu. –

+0

[Tôi đã gặp vấn đề tương tự và thấy điều này hữu ích.] (Http://jmdority.wordpress.com/2011/07/20/using-entity-framework-4-1-dbcontext-change-tracking-for-audit- log /) –

+0

Thay vào đó, tôi sẽ thực hiện một giao diện 'IAuditiable', theo cách đó bạn vẫn có thể có các thực thể không được kiểm tra và những thứ mà bạn có thể thực hiện logic cụ thể cho giao diện đó trong lời gọi SaveChanges() như được đề xuất trong một các câu trả lời dưới đây, nếu đó là những gì bạn muốn. – FRoZeN

Trả lời

0

Bạn không nên cố gắng kiểm soát quyền truy cập trực tiếp trên lớp thực thể/lớp dữ liệu của mình thay vì bạn nên làm điều này trong lớp ứng dụng của mình. Bằng cách này, bạn có một mức độ kiểm soát tốt hơn đối với những gì người dùng có thể làm những gì.

Ngoài ra thay vì có các trường kiểm tra được lặp lại trên mỗi bảng, bạn có thể lưu trữ bản ghi Kiểm tra của mình trong bảng khác. Đây là dễ dàng để làm với mã đầu tiên:

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; } 
} 

Sau đó bạn sẽ liên kết các lớp cơ sở với các hồ sơ kiểm toán với nó:

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

Và cuối cùng thực sự của bạn thực thể

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

Bạn không thể truy cập dữ liệu kiểm tra bằng cách:

Person.Audit.IsActive 
+0

Thú vị nhưng nó không đáp ứng được mục tiêu yêu cầu tạo ra và CreatedBy được dân cư khi đối tượng được tạo ra. Ngoài ra, có một bảng kiểm toán riêng biệt có nghĩa là bạn sẽ cần một khóa (không được hiển thị trong AuditClass) có thể tham chiếu đến bất kỳ khóa thực thể nào khác. Đây sẽ không phải là hình thức bình thường thứ 3. Vấn đề khác với một bảng kiểm toán chung mà tôi đã gặp phải là một vấn đề hiệu suất vì nó trở thành một cổ chai để thực hiện. – Josh

+0

@Josh: Bạn thực sự có thể giữ nguyên trong 3NF bằng cách thêm một khóa vào lớp AuditRecord và có tất cả các thực thể khác của bạn chứa một 'Danh sách ' (sẽ tạo mối quan hệ một-nhiều với tất cả các thực thể được kiểm toán của bạn và kiểm toán bàn). Điều này sẽ chỉ là một nút cổ chai cho chèn và cập nhật (nên được tối ưu hóa để được càng nhanh càng tốt anyway), vì vậy nó có thể không phải là một vấn đề tùy thuộc vào yêu cầu/thực hiện của bạn. –

5

Bạn có thể khởi tạo ngữ cảnh với một hàm tạo chấp nhận một chuỗi createdBy.Sau đó, trong một ghi đè 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(); 
} 

Với SetAuditValues() như

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

Sau khi các đối tượng đã được cụ thể hóa từ cơ sở dữ liệu các giá trị sẽ không được ghi đè khi ai đó gọi SetAuditValues.

+0

Điều này có vẻ gần, nhưng tôi vẫn có vấn đề với các cột không được tạo ra bởi vì các setters là riêng tư. Tôi có thể làm cho họ được bảo vệ, nhưng sau đó ai đó chỉ có thể gọi Person.Created = new-value. Nó sẽ không được lưu vào cơ sở dữ liệu vì SetAuditValues, nhưng nó sẽ là một trạng thái không hợp lệ trong khi trong bộ nhớ trước khi lưu. – Josh

+0

Bạn sẽ có thể thêm các thuộc tính vào mô hình bằng ánh xạ thông thạo, phải không? –

+0

Có và Không - bạn phải sử dụng trường chỉ đọc Bí danh để giải quyết vấn đề Riêng tư với bản đồ lưu loát. Các giải pháp là một chút của một hack. – Josh

Các vấn đề liên quan