2008-12-30 33 views
7

Tôi hiện đang sử dụng NHibernate làm lớp truy cập dữ liệu của mình, sử dụng Fluent NHibernate để tạo các tệp ánh xạ cho tôi. Tôi có hai lớp, TripItem và TripItemAttributeValue, có mối quan hệ nhiều-nhiều giữa chúng.NHibernate không bền bỉ mối quan hệ nhiều-nhiều-

Các bản đồ như sau:

public class TripItemMap : ClassMap<TripItem2> 
{ 
    public TripItemMap() 
    { 
     WithTable("TripItemsInt"); 
     NotLazyLoaded(); 

     Id(x => x.ID).GeneratedBy.Identity().WithUnsavedValue(0); 
     Map(x => x.CreateDate, "CreatedOn").CanNotBeNull(); 
     Map(x => x.ModifyDate, "LastModified").CanNotBeNull(); 

     /* snip */ 

     HasManyToMany<TripItemAttributeValue>(x => x.Attributes).AsBag() 
      .WithTableName("TripItems_TripItemAttributeValues_Link") 
      .WithParentKeyColumn("TripItemId") 
      .WithChildKeyColumn("TripItemAttributeValueId") 
      .LazyLoad(); 
    } 
} 

public class TripItemAttributeValueMap : ClassMap<TripItemAttributeValue> 
{ 
    public TripItemAttributeValueMap() 
    { 
     WithTable("TripItemAttributeValues"); 

     Id(x => x.Id).GeneratedBy.Identity(); 
     Map(x => x.Name).CanNotBeNull(); 

     HasManyToMany<TripItem2>(x => x.TripItems).AsBag() 
      .WithTableName("TripItems_TripItemAttributeValues_Link") 
      .WithParentKeyColumn("TripItemAttributeValueId") 
      .WithChildKeyColumn("TripItemId") 
      .LazyLoad(); 
    } 
} 

Tại một số điểm trong ứng dụng của tôi, tôi lấy thuộc tính hiện tại từ cơ sở dữ liệu, thêm chúng vào tripItem.Attributes, sau đó lưu các đối tượng tripItem. Cuối cùng, TripItems_TripItemAttributeValues_Link không bao giờ nhận được bất kỳ bản ghi mới nào, dẫn đến các mối quan hệ không được duy trì.

Nếu nó giúp, đây là các file ánh xạ được tạo ra bởi thành thạo NHibernate cho các lớp này:

<?xml version="1.0" encoding="utf-8"?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="true" assembly="ETP.Core" namespace="ETP.Core.Domain"> 
    <class name="TripItem2" table="TripItemsInt" xmlns="urn:nhibernate-mapping-2.2" lazy="false"> 
    <id name="ID" column="ID" type="Int32" unsaved-value="0"> 
     <generator class="identity" /> 
    </id> 
    <property name="CreateDate" column="CreatedOn" type="DateTime" not-null="true"> 
     <column name="CreatedOn" /> 
    </property> 
    <property name="ModifyDate" column="LastModified" type="DateTime" not-null="true"> 
     <column name="LastModified" /> 
    </property> 
    <bag name="Attributes" lazy="true" table="TripItems_TripItemAttributeValues_Link"> 
     <key column="TripItemId" /> 
     <many-to-many column="TripItemAttributeValueId" class="ETP.Core.Domain.TripItemAttributeValue, ETP.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> 
    </bag> 
    </class> 
</hibernate-mapping> 

<?xml version="1.0" encoding="utf-8"?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="true" assembly="ETP.Core" namespace="ETP.Core.Domain"> 
    <class name="TripItemAttributeValue" table="TripItemAttributeValues" xmlns="urn:nhibernate-mapping-2.2"> 
    <id name="Id" column="Id" type="Int32"> 
     <generator class="identity" /> 
    </id> 
    <property name="Name" column="Name" length="100" type="String" not-null="true"> 
     <column name="Name" /> 
    </property> 
    <bag name="TripItems" lazy="true" table="TripItems_TripItemAttributeValues_Link"> 
     <key column="TripItemAttributeValueId" /> 
     <many-to-many column="TripItemId" class="ETP.Core.Domain.TripItem2, ETP.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> 
    </bag> 
    </class> 
</hibernate-mapping> 

Tôi đang làm gì sai ở đây?

Trả lời

8

@efdee

Tôi đã gặp vấn đề tương tự và đã dành gần hai ngày cho việc này. Tôi đã có nhiều mối quan hệ và bảng liên kết cũng không được cập nhật. Tôi mới đến NHibernate, chỉ cần cố gắng tìm hiểu nó để có tất cả mọi thứ tôi nói với một hạt muối.

Vâng hóa ra là nó không thành thạo NHibernate, cũng không phải ánh xạ, nhưng tôi không hiểu NHibernate làm việc với nhiều-nhiều như thế nào. Trong mối quan hệ nhiều-nhiều, nếu các bộ sưu tập trên cả hai thực thể không được phổ biến, NHibernate không lưu giữ dữ liệu vào bảng liên kết.

Hãy nói rằng tôi có thực thể này trong nhiều-nhiều mối quan hệ:


partial class Contact 
{ 
    public string ContactName {get; set;} 
    public IList Locations {get; set;} 

} 

partial class Location 
{ 
    public string LocationName {get; set;} 
    public string LocationAddress {get;set;} 
    public IList Contacts {get;set;} 
} 

khi tôi thêm vào một vị trí để Contact.Locations, tôi phải chắc chắn rằng sự tiếp xúc cũng có mặt bên trong vị trí .Contacts.

để thêm vị trí tôi có phương thức này trong lớp Liên hệ của tôi.


public void AddLocation(Location location) 
     { 
      if (!location.Contacts.Contains(this)) 
      { 
       location.Contacts.Add(this); 
      } 
      Locations.Add(location); 
     } 

Điều này dường như đã giải quyết được vấn đề của tôi, nhưng như tôi đã nói tôi chỉ chọn NHibernate và học nó, có thể có cách tốt hơn. Nếu có ai có giải pháp tốt hơn, hãy đăng bài.

Đây là bài mà chỉ cho tôi để kiểm tra tất cả các bộ sưu tập: http://www.coderanch.com/t/217138/Object-Relational-Mapping/link-table-of-ManyToMany-annotation

2

Tôi không chắc chắn cách bạn làm điều đó với Fluent NHibernate nhưng bạn cần đặt tùy chọn Cascade trên túi (TripItems). Như thường lệ, Ayende's got a useful post about cascade options.

Từ một cách nhanh chóng của Google, tôi muốn đề nghị bạn thử:

HasManyToMany<TripItem2>(x => x.TripItems).AsBag() 
     .WithTableName("TripItems_TripItemAttributeValues_Link") 
     .WithParentKeyColumn("TripItemAttributeValueId") 
     .WithChildKeyColumn("TripItemId") 
     .LazyLoad() 
/*-->*/ .Cascade.All(); /*<-- this is the bit that should make it work */ 
1

David Kemp có đúng: bạn muốn thêm một thác túi của mình.

Tôi luôn chỉnh sửa thủ công (và tạo bằng tay) các tệp ánh xạ, do đó, độ nghiêng tự nhiên của tôi là đặt nó ở đó. Bạn có thể làm điều đó như sau:

<bag name="TripItems" lazy="true" table="TripItems_TripItemAttributeValues_Link" cascade="all"> 
    <key column="TripItemAttributeValueId" /> 
    <many-to-many column="TripItemId" class="ETP.Core.Domain.TripItem2, ETP.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> 
</bag> 

Tôi đã thấy rằng việc giữ cho lớp học của tôi 'thuần khiết' và giữ mọi thứ liên quan đến nHibernate trong tệp .hbm.xml giữ cho giải pháp của tôi sạch hơn. Bằng cách đó, nếu có một phần mềm ORM mới mà tôi muốn sử dụng, tôi chỉ thay thế các tệp ánh xạ và không viết lại các lớp đó. Chúng tôi sử dụng các bài kiểm tra Đơn vị của chúng tôi để kiểm tra các lớp học và cung cấp cho testability cho xml, mặc dù tôi làm giống như phương pháp của Fluent NHibernate.

0

Tôi sợ Cascade.All() không thực sự là giải pháp cho vấn đề của tôi - đó là một trong những điều tôi đã thử. Vấn đề không phải là các mục được thêm vào bộ sưu tập sẽ không được lưu - chúng đã có trong cơ sở dữ liệu tại thời điểm chúng được thêm vào bộ sưu tập. Nó chỉ là các mục trong bảng liên kết không được tạo ra. Hơn nữa tôi nghĩ Cascade.All() cũng sẽ khiến các mục con bị xóa, đó không phải là hành vi mong muốn trong kịch bản của tôi. Tôi đã thử sử dụng Cascade.SaveUpdate(), nhưng như tôi đã chỉ ra, điều này giải quyết một cái gì đó không thực sự là vấn đề của tôi :-)

Tuy nhiên, để đảm bảo, tôi sẽ thử lại giải pháp này và cho bạn biết kết quả.

Để giữ cho lớp học trong sạch, đây là trường hợp 100% với Fluent NHibernate. Ánh xạ lớp bạn tạo là các tệp mã C# đi cùng với các lớp thực thể của bạn, khá giống các tệp .hbm.xml.

+0

Cùng một thỏa thuận đối với tôi - xếp chồng không phải là điều tôi muốn và điều đó không giúp ích gì. Đỏ mặt là câu trả lời! –

1

Tôi đang gặp chính xác cùng một vấn đề nhưng tôi đã sử dụng NHibernate.JetDriver. Tôi đã thử sử dụng câu trả lời được đề xuất mà không thành công. Có ai biết nếu NHibernate.JetDriver có một giới hạn đối với nhiều-to-nhiều?

Dưới đây là các file hbm của tôi trong trường hợp ai đó sẽ xảy ra là quan tâm đến việc xem xét chúng trong chốc lát:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Ace.Docs.Core.Domain" assembly="Ace.Docs.Core"> 
<class name="Ace.Docs.Core.Domain.Address, Ace.Docs.Core" table="Addresses" lazy="true"> 
    <id name="Id" column="ID"> 
     <generator class="identity" /> 
    </id> 
    <property name="Address1" column="Address1" /> 
    <property name="Address2" column="Address2" /> 
    <property name="City" column="City" /> 
    <property name="EmailAddress" column="EmailAddress" /> 
    <property name="Phone1" column="Phone1" /> 
    <property name="Phone2" column="Phone2" /> 
    <property name="PostalCode" column="PostalCode" /> 
    <property name="StateOrProvince" column="StateOrProvince" /> 
    <many-to-one name="AddressTypeMember" column="AddressTypeID" class="AddressType" /> 
    <bag name="HasPersonalInfo" table="Link_PersonalInfo_Addresses" lazy="true" cascade="save-update" inverse="true" > 
     <key column="AddressID"></key> 
     <many-to-many column="PersonalInfoID" class="PersonalInfo" /> 
    </bag> 
</class> 

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Ace.Docs.Core.Domain" assembly="Ace.Docs.Core"> 
<class name="Ace.Docs.Core.Domain.PersonalInfo, Ace.Docs.Core" table="PersonalInfo" lazy="true"> 
    <id name="Id" column="ID"> 
     <generator class="identity" /> 
    </id> 
    <property name="Prefix" column="Prefix" /> 
    <property name="FirstName" column="FirstName" /> 
    <property name="MiddleName" column="MiddleName" /> 
    <property name="LastName" column="LastName" /> 
    <property name="SIN" column="SIN" /> 
    <property name="Birthdate" column="Birthdate" /> 
    <property name="Note" column="Notes" /> 
    <bag name="HasAddress" table="Link_PersonalInfo_Addresses" lazy="true" cascade="save-update" inverse="true" > 
     <key column="PersonalInfoID"></key> 
     <many-to-many column="AddressID" class="Address" /> 
    </bag> 
</class> 

1

Tôi đã có nó và tôi hy vọng điều này giúp người khác ra khỏi đó. Vấn đề là tôi đã nghịch đảo = 'true' trên cả hai túi. Nếu bạn đọc đoạn trích bên dưới, bạn sẽ lưu ý rằng cần phải đặt ngược lại thành đúng trên một trong các túi:

Lưu ý việc sử dụng nghịch đảo = "true". Một lần nữa, thiết lập này cho NHibernate bỏ qua những thay đổi được thực hiện cho bộ sưu tập danh mục và sử dụng đầu kia của kết hợp - bộ sưu tập các mục - như là biểu diễn cần được đồng bộ hóa với cơ sở dữ liệu.

0

Tôi đã đấu tranh với điều này là tốt, và đến bởi một lý do hoàn toàn khác nhau cho những rắc rối của tôi. Trong ví dụ của tôi nếu tôi đã có một đối tượng mà không có bất kỳ mối quan hệ nhiều-nhiều, tôi chỉ có thể gọi saveOrUpdate, và tất cả sẽ là tốt. Nhưng nếu tôi có bất kỳ mối quan hệ nhiều-nhiều, tôi đã phải chắc chắn rằng cuộc gọi saveOrUpdate của tôi nằm trong một BeginTransaction và CommitTransaction. Tôi rất mới thông thạo Nhibernate, vì vậy xin lỗi nếu điều này là hiển nhiên. Nhưng không phải với tôi.

7

Cuộc gọi Session.Flush() hoặc sử dụng giao dịch.

+0

Cảm ơn! Tôi gặp vấn đề tương tự. Tôi đã gọi Session.SaveOrUpdate (thực thể) cho một bên của mối quan hệ. Nhưng điều này không tạo ra bảng liên kết. Gọi Session.Flush() đã giải quyết vấn đề này. –

+0

Điều này làm việc cho tôi quá ... làm thế nào gây phiền nhiễu! – Paul

+3

Bất cứ ai có thể giải thích TẠI SAO chúng ta cần phải làm điều này trong trường hợp này? – Oliver

2

Tôi cũng gặp phải vấn đề tương tự - dữ liệu kết nối của nhiều người không được duy trì. Tôi đã sao chép ánh xạ từ một mối quan hệ nhiều-một-một (sửa đổi nó cho một rel nhiều-nhiều) nhưng giữ lại một thuộc tính nghịch đảo = "true". Khi tôi xóa thuộc tính này, sự cố đã được giải quyết.

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