2012-05-08 24 views
8

Tôi muốn có tham chiếu giữa hai thực thể được lưu trữ trong cơ sở dữ liệu tài liệu RavenDB. Vì đây không phải là một db quan hệ tôi biết rằng tôi phải sử dụng kỹ thuật Tham chiếu không chuẩn hóa được mô tả trong tài liệu RavenDBs. Mặc dù lúc đầu điều này có vẻ ổn, một khi tôi bắt đầu tạo ra một "hệ thống phân cấp" miền thực tế bao gồm cả tham chiếu hai chiều, nỗ lực giữ tất cả các tài liệu tham khảo đó không bị ảnh hưởng. Tôi cảm thấy tôi có thể đang đi sai ở đâu đó.Làm cách nào để triển khai các Tham chiếu không chuẩn hóa trong RavenDB

Bạn có thể giải thích cách tốt nhất/đơn giản nhất để lập mô hình phân cấp miền phức tạp hợp lý bằng RavenDB không?

Cảm ơn

+0

Bài đăng trên blog này có thể giúp bạn quyết định: http://daniellang.net/how-to-handle-relations-in-ravendb/ – dasheddot

+0

Cảm ơn dasheddot, điều đó thực sự hữu ích, cảm ơn bạn. –

+0

Điều này có vẻ thú vị. Multi Maps/Giảm chỉ mục [tại đây] (http: // ayende.com/blog/89089/ravendb-multi-maps-reduce-indexes) – biofractal

Trả lời

6

Tôi không chắc chắn liệu điều này sẽ đi xa đủ để trả lời câu hỏi của bạn, nhưng đây là cách tôi đi về việc tạo ra một tham khảo denormalized trong RavenDB (điều này được lấy từ mã thực với những người không cần thiết loại bỏ cho rõ ràng)

miền

public class User : IUserIdentity 
{ 
    public string UserName { get; set; } 
    public IEnumerable<string> Claims { get; set; } 
    public string Id { get; set; } 
    public Guid FormsAuthenticationGuid { get; set; } 
} 

public class Assessment 
{ 
    public string Id { get; set; } 
    public UserReference User { get; set; } 
    public AssessmentState State { get; set; } 
} 

Bạn có thể thấy rằng tôi có một lớp Assessment tham chiếu đến một User. Tham chiếu người dùng này được quản lý bằng cách sử dụng lớp học UserReference bên dưới.

denormalized Reference

public class UserReference 
{ 
    public string Id { get; set; } 
    public string UserName { get; set; } 

    public static implicit operator UserReference(User user) 
    { 
     return new UserReference 
       { 
         Id = user.Id, 
         UserName = user.UserName 
       }; 
    } 
} 

Lưu ý cách lớp tham chiếu cũng mang UserName. Giá trị này sẽ không thay đổi thường xuyên nhưng nó có thể thay đổi vì vậy chúng tôi cần một cách để cập nhật thuộc tính UserName trong thuộc tính UserReference được giữ trong lớp Assessment. Để thực hiện thay đổi, trước hết chúng ta phải tìm đúng Assessment trường hợp từ RavenDB và cho rằng chúng ta cần một chỉ mục.

Raven Index

public class Assessment_ByUserId : AbstractIndexCreationTask<Assessment> 
{ 
    public Assessment_ByUserId() 
    { 
     Map = assessments => from assessment in assessments 
           select new 
            { 
              User_Id = assessment.User.Id 
            }; 
    } 
} 

chỉ số này cần phải được gọi bất cứ khi nào giá trị của một User 's UserName được cập nhật. Tôi có một lớp học UserService giúp tôi phối hợp tất cả các chức năng liên quan đến Người dùng của tôi, vì vậy đó là nơi tôi đặt mã này.

Tôi sử dụng lại mã này cho các tài liệu tham khảo khác để nó được trừu tượng hóa một chút. Điều này có thể giúp bạn tạo ra các cấu trúc phân cấp phức tạp hơn (hoặc có thể là 'biểu đồ miền' là mô tả tốt hơn) mà bạn muốn.

UserService

public static void SetUserName(IDocumentSession db, string userId, string userName) 
{ 
    var user = db.Load<User>(userId); 
    user.UserName = userName; 
    db.Save(user); 
    UpdateDenormalizedReferences(db, user, userName); 
} 

private static void UpdateDenormalizedReferences(IDocumentSession db, User user, string userName) 
{ 
    db.Advanced.DatabaseCommands.UpdateByIndex(
      RavenIndexes.IndexAssessmentByUserId, 
      GetQuery(user.Id), 
      GetUserNamePatch(userName), 
      allowStale: true); 

} 

private static IndexQuery GetQuery(string propertyValue, string propertyName = "User_Id") 
{ 
    return new IndexQuery {Query = string.Format("{0}:{1}", propertyName, propertyValue)}; 
} 

private static PatchRequest[] GetUserNamePatch(string referenceValue, string referenceName = "User") 
{ 
    return new[] 
      { 
        new PatchRequest 
        { 
          Type = PatchCommandType.Modify, 
          Name = referenceName, 
          Nested = new[] 
            { 
              new PatchRequest 
              { 
                Type = PatchCommandType.Set, 
                Name = "UserName", 
                Value = referenceValue 
              } 
            } 
        } 
      }; 
} 

Đó là nó. Và bạn biết đấy, bây giờ tôi đặt tất cả ra tôi có thể thấy những gì bạn có ý nghĩa. Nó rất nhiều công việc chỉ để cập nhật một tham chiếu. Có lẽ mã dịch vụ có thể được thực hiện nhiều DRY và tái sử dụng cho các loại mối quan hệ khác nhau, nhưng tôi không thấy làm thế nào để tránh xa việc viết nhiều chỉ mục, mỗi loại được tham chiếu.

+0

Tuyệt vời, nhờ biofractal, tôi đã cố gắng một con đường phức tạp hơn nhiều, điều này có vẻ lý tưởng. –

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