2011-11-05 34 views
5

Giả sử tôi có hai loại sau đây:Tránh xác định cột quan trọng trong việc tăng gấp đôi liên kết kịch bản

public class User : Entity 
{ 
    public virtual IList<Item> Items { get; set; } 
} 

public class Item : Entity 
{ 
    public virtual User Owner { get; set; } 
} 

Tôi tạo ra hai lớp bản đồ:

public class UserMap : ClassMap<User> 
{ 
    public UserMap() 
    { 
     Id(x => x.Id); 
     HasMany(x => x.Items); 
    } 
} 

public class ItemMap : ClassMap<Item> 
{ 
    public ItemMap() 
    { 
     Id(x => x.Id); 
     References(x => x.Owner); 
    } 
} 

này sẽ cho kết quả trong một bảng Item mà có một cột UserId và một cột OwnerId. Khi tôi sử dụng KeyColumn("OwnerId") trên ánh xạ HasMany, nó chỉ hoạt động với cột OwnerId, nhưng tôi muốn tránh điều đó. Có cách nào để nói với NHibernate, sử dụng cột được tạo ra bởi ánh xạ trong ItemMap?

Tại sao tôi muốn tránh chỉ định cột một cách rõ ràng:
Tên cột OwnerId được tạo tự động dựa trên tên của thuộc tính và một số quy tắc. Nếu tôi thay đổi quy tắc hoặc tên thuộc tính, tôi cũng cần phải nhớ thay đổi điều đó là KeyColumn. Vì vậy, về cơ bản, nó không phải là tái cấu trúc tiết kiệm.

+0

Bạn có thể đổi tên thuộc tính thành Người dùng không? công cộng người dùng ảo {get; bộ; }. Bạn sẽ phải thay đổi ánh xạ tham chiếu của bạn quá tất nhiên –

+0

@ColeW: Vâng, việc thay đổi thuộc tính thành Người dùng rõ ràng sẽ sửa lỗi đó, nhưng hơn tên của thuộc tính sẽ không tốt như bây giờ. –

+0

Tôi đồng ý nhưng tôi không nghĩ rằng có cách làm sạch những gì bạn đang yêu cầu khác. –

Trả lời

2

Cập nhật: cố định lỗi

nếu bạn áp dụng các quy tắc trong các bản đồ sau đó

public static void KeyColumnFromReference<TChild>(
    this OneToManyPart<TChild> collectionmap, ClassMap<TChild> map, Expression<Func<TChild, object>> referenceprop) 
{ 
    string propertyname = GetPropertyName(referenceprop); 
    var column = ((IMappingProvider)map).GetClassMapping() 
     .References.First(m => m.Name == propertyname) 
     .Columns.First().Name; 

    collectionmap.KeyColumn(column); 
} 

public static void KeyColumnFromReference<T, TChild>(
    this OneToManyPart<TChild> collectionmap, ClassMap<TChild> map) 
{ 
    var column = ((IMappingProvider)map).GetClassMapping() 
     .References.First(m => m.Type == typeof(TChild)) 
     .Columns.First().Name; 

    collectionmap.KeyColumn(column); 
} 

public UserMap() 
{ 
    HasMany(x => x.Items) 
     .KeyColumnFromReference<User, Item>(new ItemMap()); 

    // or 

    HasMany(x => x.Items) 
     .KeyColumnFromReference(new ItemMap(), u => u.Owner); 
} 

nếu bạn áp dụng các quy tắc như công ước thì bạn cần phải thực hiện IHasManyConvention và áp dụng các quy tắc tương tự trên EntityType và propertyname (mà bạn phải trải qua sự phản chiếu từ ChildType)

Cập nhật:

class ForeignKeyConvention : IHasManyConvention 
{ 
    public void Apply(IOneToManyCollectionInstance instance) 
    { 
     // to force the compiler to take the Name property and not the Name method 
     string propertyName = ((ICollectionInspector)instance).Name; 

     // should be equal to the convention for the reference key column 
     instance.Key.Column(propertyName + instance.EntityType.Name + "id"); 
    } 
} 
+0

Cảm ơn, điều đó có vẻ tốt. Tuy nhiên, tôi tự hỏi bạn có chắc là mã này đang hoạt động không. Nó trông giống như đệ quy vô tận đối với tôi: Trong ctor của 'UserMap', bạn tạo một thể hiện mới của' UserMap' ... Sẽ không tốt hơn nếu chỉ cần truyền 'this'? –

+0

một lỗi thx, cố định. thực sự đây là một cú đánh nhanh;) – Firo

+0

Cảm ơn bạn đã viết mã - Tôi vừa thử nghiệm nó. Thật không may, có một vấn đề còn lại: Nó không có các quy ước để định dạng các khóa ngoại vào tài khoản ... Bạn có thể vui lòng cập nhật mã của bạn cho phù hợp? Mẫu: Công ước của tôi là thêm "Id" vào tên thuộc tính. Mã của bạn nối thêm "_id". –

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