2009-04-27 16 views
8

Tôi mới dùng nHibernate, và cố gắng để có được đầu của tôi xung quanh cách thích hợp để cập nhật các đối tượng tách ra từ một POST mẫu ứng dụng web. (Chúng tôi đang sử dụng ASP.NET MVC)Cách thích hợp để cập nhật thực thể nhibernate từ phương thức hành động POST asp.net là gì?

Đối tượng Tôi đang cố gắng để cập nhật chứa (trong số những thứ khác) một IList của các đối tượng trẻ em, ánh xạ một cái gì đó như thế này:

<bag name="PlannedSlices" inverse="true" cascade="all-delete-orphan"> 
     <key column="JobNumber" /> 
     <one-to-many class="SliceClass" /> 
</bag> 

Chúng tôi đã sắp xếp của chúng tôi MVC chỉnh sửa xem hình thức để khi nó được đăng trở lại, phương pháp hành động của chúng tôi được thông qua am đối tượng (incluing Danh sách <> của các mặt hàng con.Chúng tôi round-trip tất cả các ID của tổ chức một cách chính xác thông qua các hình thức. phương thức hành động post thực hiện một session.SaveOrUpdate (parentObject), với parentObject đã được cạo từ dạng xem theo chế độ mặc định lbinder.

Điều này dường như làm việc tốt cho bất kỳ tình huống sau đây:

  • Tạo một đối tượng cha mẹ mới
  • Sửa đổi thuộc tính của cha mẹ
  • Thêm con mới đối tượng
  • Sửa đổi con hiện có đối tượng (Nhìn vào các bản ghi nHibernate, tôi có thể thấy nó được thiết lập chính xác nếu các đối tượng là mới hoặc hiện có và phát hành UPDATE hoặc INSERT thích hợp)

Kịch bản thất bại là: - Xóa đối tượng con - nghĩa là nếu chúng không nằm trong IList, chúng sẽ không bị xóa khỏi cơ sở dữ liệu. Không có ngoại lệ hoặc bất cứ điều gì, họ chỉ không bị xóa.

Sự hiểu biết của tôi là vì ma thuật mà nHibernate thực hiện để tạo danh sách trẻ em yêu cầu xóa không hoạt động với các cá thể tách rời.

Tôi đã không thể tìm thấy một ví dụ đơn giản về phương thức hành động này sẽ như thế nào với nHibernate (ví dụ: sử dụng đối tượng mô hình kết hợp như một cá thể nHibernate tách rời) - ví dụ dựa trên MS EF (ví dụ: http://stephenwalther.com/blog/archive/2009/02/27/chapter-5-understanding-models.aspx) dường như sử dụng phương thức 'ApplyPropertyChanges' để sao chép các thuộc tính đã thay đổi từ đối tượng mô hình bị ràng buộc sang đối tượng thực thể được nạp lại. Vì vậy, sau khi tất cả, câu hỏi là khá đơn giản - nếu tôi có chất kết dính mô hình cho tôi một đối tượng mới có chứa bộ sưu tập các đối tượng con, làm thế nào tôi nên cập nhật thông qua nHibernate, (nơi 'cập nhật' bao gồm có thể xóa của trẻ em)?

Trả lời

4

Đây là một ví dụ làm những gì tôi nghĩ bạn đang cố gắng làm. Hãy cho tôi biết nếu tôi đã hiểu lầm những gì bạn đang cố gắng làm.

Do sau "miền" lớp:

public class Person 
{ 
    private IList<Pet> pets; 

    protected Person() 
    { } 

    public Person(string name) 
    { 
     Name = name; 
     pets = new List<Pet>(); 
    } 

    public virtual Guid Id { get; set; } 
    public virtual string Name { get; set; } 
    public virtual IEnumerable<Pet> Pets 
    { 
     get { return pets; } 
    } 

    public virtual void AddPet(Pet pet) 
    { 
     pets.Add(pet); 
    } 

    public virtual void RemovePet(Pet pet) 
    { 
     pets.Remove(pet); 
    } 
} 

public class Pet 
{ 
    protected Pet() 
    { } 

    public Pet(string name) 
    { 
     Name = name; 
    } 

    public virtual Guid Id { get; set; } 
    public virtual string Name { get; set; } 
} 

Với các bản đồ sau:

public class PersonMap : ClassMap<Person> 
    { 
     public PersonMap() 
     { 
      LazyLoad(); 
      Id(x => x.Id).GeneratedBy.GuidComb(); 
      Map(x => x.Name); 
      HasMany(x => x.Pets) 
        .Cascade.AllDeleteOrphan() 
        .Access.AsLowerCaseField() 
        .SetAttribute("lazy", "false"); 
     } 
    } 

    public class PetMap : ClassMap<Pet> 
    { 
     public PetMap() 
     { 
      Id(x => x.Id).GeneratedBy.GuidComb(); 
      Map(x => x.Name); 
     } 
    } 

thử nghiệm này:

[Test] 
    public void CanDeleteChildren() 
    { 
     Person person = new Person("joe"); 

     Pet dog = new Pet("dog"); 
     Pet cat = new Pet("cat"); 

     person.AddPet(dog); 
     person.AddPet(cat); 

     Repository.Save(person); 

     UnitOfWork.Commit(); 

     CreateSession(); 
     UnitOfWork.BeginTransaction(); 

     Person retrievedPerson = Repository.Get<Person>(person.Id); 
     Repository.Evict(retrievedPerson); 

     retrievedPerson.Name = "Evicted"; 

     Assert.AreEqual(2, retrievedPerson.Pets.Count()); 
     retrievedPerson.RemovePet(retrievedPerson.Pets.First()); 

     Assert.AreEqual(1, retrievedPerson.Pets.Count()); 

     Repository.Save(retrievedPerson); 

     UnitOfWork.Commit(); 

     CreateSession(); 
     UnitOfWork.BeginTransaction(); 

     retrievedPerson = Repository.Get<Person>(person.Id); 
     Assert.AreEqual(1, retrievedPerson.Pets.Count()); 
    } 

chạy và tạo ra sql sau:

XóaChildrenOfEvictedObject.CanDeleteChildren: Đã vượt qua NHibernate: INSERT INTO GIÁ TRỊ [Tên] (Tên, Id) (@ p0, @ p1); @ p0 = 'joe', @ p1 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2'

NHibernate: INSERT INTO [Pet] (Tên, Id) GIÁ TRỊ (@ p0, @ p1); @ p0 = 'chó', @ p1 = '464e59c7-74d0-4317-9c22-9bf801013abb'

NHibernate: INSERT INTO [Pet] (Tên, Id) GIÁ TRỊ (@ p0, @ p1); @ p0 = 'cat', @ p1 = '010c2fd9-59c4-4e66-94fb-9bf801013abb'

NHibernate: UPDATE [Pet] SET Person_id = @ p0 WHERE Id = @ p1; @ p0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2', @ p1 = '464e59c7-74d0-4317-9c22-9bf801013abb'

NHibernate: UPDATE [Pet] SET Person_id = @ p0 WHERE Id = @ p1; @ P0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2', @ p1 = '010c2fd9-59c4-4e66-94fb-9bf801013abb'

NHibernate: SELECT person0_.Id như Id5_0_, person0_.Name như Name5_0_ FROM [Person ] person0_ WHERE [email protected]; @ P0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2'

NHibernate: SELECT pets0_.Person_id như Person3_1_, pets0_.Id như Id1_, pets0_.Id như Id6_0_, pets0_.Name như Name6_0_ FROM [Pet] pets0_ Ở ĐÂU [email protected]; @ p0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2'

NHibernate: UPDATE [Người] SET Name = @ p0 WHERE Id = @ p1; @ p0 = 'Bị đuổi', @ p1 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2'

NHibernate: UPDATE [Pet] SET Name = @ p0 WHERE Id = @ p1; @ p0 = 'chó', @ p1 = '464e59c7-74d0-4317-9c22-9bf801013abb' NHibernate: UPDATE [Pet] SET Person_id = null WHERE Person_id = @ p0 AND Id = @ p1; @ p0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2', @ p1 = '010c2fd9-59c4-4e66-94fb-9bf801013abb'

NHibernate: DELETE FROM [Pet] WHERE Id = @ p0; @ P0 = '010c2fd9-59c4-4e66-94fb-9bf801013abb'

NHibernate: SELECT person0_.Id như Id5_0_, person0_.Name như Name5_0_ FROM [Người] person0_ ĐÂU [email protected]; @ P0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2'

NHibernate: SELECT pets0_.Person_id như Person3_1_, pets0_.Id như Id1_, pets0_.Id như Id6_0_, pets0_.Name như Name6_0_ FROM [Pet] pets0_ Ở ĐÂU [email protected]; @ P0 = 'cd123fc8-6163-42a5-aeeb-9bf801013ab2'

Lưu ý DELETE FROM [Pet] ...

như vậy, những gì bạn cần để có thể làm là tay nhibernate một đối tượng Person (trong ví dụ này) với các bộ sưu tập đã sửa đổi và nó sẽ có thể xác định những gì cần xóa. Đảm bảo bạn có thuộc tính Cascade.AllDeleteOrphan().

+0

Cảm ơn rất nhiều vì điều này - rất nhiều công việc ở đó! Thật không may, bit mà tôi đang gặp phải là đối tượng 'Person' tôi có trong phiên thứ hai/giao dịch (tức là POST của tôi) là một đối tượng hoàn toàn mới được tạo bởi ModelBinder, chứ không phải là đối tượng đã truy xuất đã có vài trường đã được sửa đổi và có một vài cuộc gọi 'xóa con' được thực hiện trên đó. Tôi nghĩ rằng những gì tôi đang tìm kiếm là một cách để lấy đối tượng mới đó và áp dụng các thay đổi của nó cho đối tượng đã truy xuất, để sau đó nh có thể làm việc với SQL cần thiết. Có lẽ điều đó không tồn tại. –

+1

Cách tôi có xu hướng đối phó với tình huống đó là bằng cách xử lý đối tượng mới được tạo bởi trình kết nối mô hình làm đối tượng Mô hình trình bày. Bạn sẽ vẫn cần truy xuất đối tượng (hoặc bằng cách nào đó tạo một thể hiện của lớp "persisted") mà bạn muốn cập nhật và áp dụng các bản cập nhật đó cho đối tượng đó. Sau đó bạn có thể lưu đối tượng đó vào NHibernate. Điều đó có ý nghĩa? –

+0

Vì vậy, bạn sẽ 'theo cách thủ công' (nghĩa là thuộc tính, theo vòng hoặc bất kỳ bộ sưu tập con nào), ghi đè lên các thuộc tính của đối tượng 'được truy xuất' với thuộc tính của đối tượng 'bản trình bày (tức là POST)'? Và tự tính toán các yêu cầu xóa trẻ em? Có vẻ là một công việc nhiều hơn một chút (và bảo trì!) Hơn tôi đã hy vọng. Dường như có vẻ đáng làm phiền với người mô hình, thực sự, như thể tôi phải xử lý từng lĩnh vực một lần tôi cũng có thể kéo họ thẳng từ phản hồi của biểu mẫu. Cảm ơn sự giúp đỡ của bạn. –

1

Câu trả lời của Rob thuyết phục tôi xem xét kỹ hơn việc tải mục hiện có vào phiên mới và sau đó hợp nhất phương pháp tiếp cận, và dĩ nhiên có ISession.Merge, dường như thực hiện chính xác những gì tôi muốn. một đối tượng mới và hợp nhất nó với người tiền nhiệm mới được tải lại vào phiên thứ hai.

Vì vậy, tôi nghĩ câu trả lời cho câu hỏi mà tôi đã cố hỏi là "tải lại thực thể hiện tại và sau đó gọi 'ISession.Merge' với thực thể mới."

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