2010-09-27 35 views
9

Cơ sở dữ liệu của tôi có cột 'LastModifiedUser' trên mỗi bảng mà tôi dự định thu thập người dùng đã đăng nhập từ một ứng dụng thực hiện thay đổi. Tôi không nói về người dùng cơ sở dữ liệu vì vậy về cơ bản đây chỉ là một chuỗi trên mỗi thực thể. Tôi muốn tìm cách để mặc định điều này cho mỗi thực thể để các nhà phát triển khác không phải nhớ gán nó bất cứ khi nào họ khởi tạo thực thể.Khuôn khổ thực thể - Hoạt động kiểm toán

Vì vậy, một cái gì đó như thế này sẽ xảy ra:

using (EntityContext ctx = new EntityContext()) 
{ 
    MyEntity foo = new MyEntity(); 

    // Trying to avoid having the following line every time 
    // a new entity is created/added. 
    foo.LastModifiedUser = Lookupuser(); 

    ctx.Foos.Addobject(foo); 
    ctx.SaveChanges(); 
} 

Trả lời

23

Có một cách hoàn hảo để thực hiện điều này trong EF 4,0 bằng cách tận dụng ObjectStateManager

Trước tiên, bạn cần phải tạo ra một lớp học phần cho ObjectContext của bạn và đăng ký đến ObjectContext.SavingChanges Event. Nơi tốt nhất để đăng ký sự kiện này là bên trong phương thức OnContextCreated. Phương pháp này được gọi bằng constructor đối tượng bối cảnh và quá tải nhà xây dựng mà là một phương pháp một phần không có thực hiện:

partial void OnContextCreated() { 
    this.SavingChanges += Context_SavingChanges; 
} 


Bây giờ mã thực tế sẽ thực hiện công việc:

void Context_SavingChanges(object sender, EventArgs e) { 

    IEnumerable<ObjectStateEntry> objectStateEntries = 
     from ose 
     in this.ObjectStateManager.GetObjectStateEntries(EntityState.Added 
                 | EntityState.Modified) 
     where ose.Entity != null 
     select ose; 

    foreach (ObjectStateEntry entry in objectStateEntries) { 

     ReadOnlyCollection<FieldMetadata> fieldsMetaData = entry.CurrentValues 
       .DataRecordInfo.FieldMetadata; 

     FieldMetadata modifiedField = fieldsMetaData 
      .Where(f => f.FieldType.Name == "LastModifiedUser").FirstOrDefault(); 

     if (modifiedField.FieldType != null) { 

      string fieldTypeName = modifiedField.FieldType.TypeUsage.EdmType.Name;      
      if (fieldTypeName == PrimitiveTypeKind.String.ToString()) { 
       entry.CurrentValues.SetString(modifiedField.Ordinal, Lookupuser()); 
      } 
     } 
    } 
} 

Mã Giải thích:
Mã này nằm bất kỳ Đã thêm hoặc Sửa đổi mục nhập có thuộc tính LastModifiedUser và sau đó cập nhật thuộc tính với giá trị đến từ phương thức Lookupuser() tùy chỉnh của bạn.

Trong khối foreach, truy vấn cơ bản khoan vào CurrentValues của mỗi mục nhập. Sau đó, sử dụng phương pháp đâu, nó nhìn vào tên của từng hạng mục FieldMetaData cho entry đó, nhặt chỉ những người có NameLastModifiedUser. Tiếp theo, câu lệnh if xác minh rằng thuộc tính LastModifiedUser là trường String; sau đó nó cập nhật giá trị của trường.

Một cách khác để treo lên phương pháp này (thay vì đăng ký vào SavingChanges sự kiện) là bằng cách ghi đè các ObjectContext.SaveChanges Method.

Bằng cách này, các mã trên thuộc về Julie Lerman từ cuốn sách Programming Entity Framework cô.


EDIT cho Tự theo dõi POCO Thực hiện:

Nếu bạn có POCOs theo dõi tự sau đó những gì tôi sẽ làm là đầu tiên tôi thay đổi mẫu T4 để gọi phương thức OnContextCreated(). Nếu bạn nhìn vào tệp ObjectContext.tt của mình, có một phương thức Initializeext() Initialize() được gọi bởi tất cả các hàm tạo, do đó một ứng cử viên tốt để gọi phương thức OnContextCreated() của chúng ta, vì vậy tất cả những gì chúng ta cần làm là thay đổi ObjectContext.tt tệp như sau:

private void Initialize() 
{ 
    // Creating proxies requires the use of the ProxyDataContractResolver and 
    // may allow lazy loading which can expand the loaded graph during serialization. 
    ContextOptions.ProxyCreationEnabled = false; 
    ObjectMaterialized += new ObjectMaterializedEventHandler(HandleObjectMaterialized); 
    // We call our custom method here: 
    OnContextCreated(); 
} 

Và điều này sẽ khiến OnContextCreated() của chúng tôi được tạo khi tạo ra bối cảnh.

Bây giờ nếu bạn đặt POCO của bạn sau ranh giới dịch vụ, thì điều đó có nghĩa là ModifiedUserName phải đi kèm với phần còn lại của dữ liệu từ người tiêu dùng dịch vụ WCF của bạn. Bạn có thể phơi bày LastModifiedUser khách sạn này để họ cập nhật hoặc nếu nó lưu trữ trong tài sản khác và bạn muốn cập nhật LastModifiedUser từ tài sản đó, sau đó bạn có thể chỉnh sửa mã thứ 2 như sau:


foreach (ObjectStateEntry entry in objectStateEntries) { 

    ReadOnlyCollection fieldsMetaData = entry.CurrentValues 
      .DataRecordInfo.FieldMetadata; 

    FieldMetadata sourceField = fieldsMetaData 
      .Where(f => f.FieldType.Name == "YourPropertyName").FirstOrDefault();    

    FieldMetadata modifiedField = fieldsMetaData 
     .Where(f => f.FieldType.Name == "LastModifiedUser").FirstOrDefault(); 

    if (modifiedField.FieldType != null) { 

     string fieldTypeName = modifiedField.FieldType.TypeUsage.EdmType.Name; 
     if (fieldTypeName == PrimitiveTypeKind.String.ToString()) { 
      entry.CurrentValues.SetString(modifiedField.Ordinal, 
        entry.CurrentValues[sourceField.Ordinal].ToString()); 
     } 
    } 
} 


Hy vọng điều này sẽ hữu ích.

+0

Cảm ơn cho câu trả lời. Tôi đã xem xét mô hình này trước đây nhưng không bao giờ có thể nhận được sự kiện onContextCreated để kích hoạt. – Biggle10

+1

Không sao cả. Như tôi đã nói, OnContextCreated không phải là một sự kiện, nó chỉ là một phương thức từng phần không có thực hiện được gọi bởi hàm tạo của đối tượng ngữ cảnh và các quá tải của hàm tạo. Tất cả những gì bạn cần làm là tạo một lớp một phần cho bối cảnh của bạn và đặt đoạn mã 1 của tôi vào trong nó. Hãy làm như vậy và cho tôi biết cách nó hoạt động cho bạn, và nếu nó vẫn không hoạt động, chúng tôi sẽ làm cho nó hoạt động! –

+0

Thực ra, tôi đã nghĩ về điều này sai và do đó mô tả nó sai. Hãy để tôi tinh chỉnh câu hỏi của mình ... Chúng tôi sử dụng các thực thể tự theo dõi và chúng được phục vụ thông qua một dịch vụ WCF cho giao diện người dùng. Khi chúng được trả lại, chúng ta sẽ gắn lại với bối cảnh và lưu lại. Nếu chúng được sửa đổi trong khi sở hữu của khách hàng, người dùng LastModified cần phản ánh điều đó. Máy chủ không có quyền truy cập để biết ai là người dùng hiện tại nên không thể là người chịu trách nhiệm thiết lập người dùng. Tôi cho rằng trong lý thuyết rằng tôi muốn làm một cái gì đó giống như một sự kiện/phương thức một phần được điều chỉnh ở cấp thực thể? – Biggle10

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