2012-10-04 2 views
7

Tôi có một người dùng có một số vai trò. Người dùng được liên kết với các vai trò bằng cách sử dụng bảng thực thể liên kết. Tôi đã thiết lập các tập tin cấu hình để thác xóa các thực thể liên kết vai trò người dùng khi người dùng bị xóa.Tại sao Session.Evict trong OnPostUpdate gây ra ngoại lệ "Có thể nonthreadsafe truy cập vào phiên"?

Chúng tôi hiện đang sử dụng xóa mềm để xóa đối tượng. Chúng tôi đã thêm trình xử lý sự kiện xóa mềm được kích hoạt bởi xóa. Khi một thực thể bị xóa, nó sẽ kích hoạt sự kiện DeleteEntity đánh dấu thực thể là đã xóa.

Chúng tôi cũng có ghi đè sự kiện OnPostUpdate để xóa các thực thể khỏi bộ nhớ cache bằng cách gọi Evict trên thực thể.

Nếu tôi tạo người dùng mà không có bất kỳ vai trò nào, sau đó xóa nó, mọi thứ hoạt động tốt (nó cũng hoạt động nếu bị vô hiệu hóa thác). Tuy nhiên nếu tôi có một người dùng với ít nhất một vai trò được giao và tôi xóa người dùng, sau khi cuộc gọi đến Evict trong OnPostUpdate, tôi nhận được một ngoại lệ NHibernate "NHibernate.AssertionFailure: Có thể nonthreadsafe truy cập vào phiên".

Tôi đã thử, trong OnPostUpdate, để sử dụng phiên con để Loại bỏ thực thể, ngoại lệ không được ném, tuy nhiên, pháp nhân không bị đuổi.

public void UserDelete(.....) 
{ 
    var user = repository.Fetch<User>(id); 

    repository.Remove(user); 
    repository.Connection.Commit(); 
} 


// soft delete event listener 
protected override void DeleteEntity(NHibernate.Event.IEventSource session, object entity, ..) 
{    
    var repositoryEntity = entity as deletableentity; 
    if (repositoryEntity != null) 
    { 
     if (!repositoryEntity.IsDeleted) 
     { 
      // this marks the entity as deleted 
      repositoryEntity.isDeleted = true; 

      // cascade delete 
      this.CascadeBeforeDelete(session, persister, repositoryEntity, entityEntry, transientEntities); 
      this.CascadeAfterDelete(session, persister, repositoryEntity, transientEntities);   
     } 
    } 
} 

public void OnPostUpdate(PostUpdateEvent @event) 
{ 
    if (@event == null) throw new ArgumentNullException("event"); 

    var entity = @event.Entity as deletableentity; 

    // Evict any entities that have been set as deleted from first level cache. 
    if (entity != null && entity.IsDeleted) 
    { 
     @event.Session.Evict(entity); 
    } 
} 

Mọi ý tưởng về cách giải quyết?

Trả lời

3

Tìm thấy sự cố là gì. Sử dụng xóa mềm sẽ thực sự kích hoạt cập nhật để đặt cờ được gắn cờ. Vì dòng này trong một ánh xạ

cascade="all" 

thác được áp dụng cho cả Update và Gỡ bỏ hành động. PostUpdate của tôi sẽ bị sa thải 2 lần, nhưng đồng thời Evict sẽ cố gắng đuổi ra khỏi các thực thể con.

Giải pháp là xóa Evict khỏi tầng trong tệp ánh xạ. Bây giờ nó là:

cascade="persist, merge, save-update, delete, lock, refresh" 
+0

cảm ơn bạn rất nhiều! – KeatsPeeks

1

Tôi chạy vào cùng một vấn đề, nhưng kể từ khi tôi đang sử dụng ánh xạ thạo không có tùy chọn để loại trừ Evict từ thác. Giải pháp của tôi là để tránh gọi Evict và chỉ cần loại bỏ các thực thể từ bộ nhớ cache session:

public void OnPostUpdate(PostUpdateEvent @event) 
{ 
    var entity = @event.Entity as ISoftDeletable; 
    if (entity != null && entity.Deleted) 
    { 
     IEventSource session = @event.Session; 
     IEntityPersister persister = @event.Persister; 

     var key = new EntityKey(@event.Id, persister, session.EntityMode); 
     session.PersistenceContext.RemoveEntity(key); 
     session.PersistenceContext.RemoveProxy(key); 
    } 
} 
+0

wow Tôi không thể tin hibernate yêu cầu như vậy shenanigans ... – rogerdpack

11

Theo https://forum.hibernate.org/viewtopic.php?p=2424890 một cách khác để tránh tình trạng này là cơ bản gọi

  session.save(s); 
      session.flush(); // allow evict to work 
      session.evict(s); 

và rằng gốc rễ của vấn đề đó là "nếu tôi đã gỡ bỏ thực thể khỏi bộ nhớ cache thì commit() sẽ không tìm thấy nó ở đó" (nghĩa là nó không phải là vấn đề an toàn của luồng, đó là một bộ đệm đã được sửa đổi).

+0

Đây cũng là vấn đề của tôi, mặc dù tôi đã sử dụng Hibernate thông qua giao diện JPA và đã được giao dịch với em.persist (...), em.flush() và em.detach (...). – kilo

+3

Vì vậy, trường hợp là "thực thể mới được tạo ra đã được tách ra (gỡ bỏ) từ phiên trước khi nó được lưu vào DB" – Lu55