사용자가 Windows Forms 응용 프로그램의 데이터베이스에서 개체를 편집하고 데이터베이스 제약 조건 (예 : 열 고유 값)을 위반하는 편집을 수행하고, 엔티티가 데이터베이스로 되돌아 간다. 그리고 NHibernate는 예외를 던져 세션을 파기한다.NHibernate를 사용하여 Winforms에서 제약 조건 위반 처리
MSDN 문서 Building a Desktop To-Do Application with NHibernate에 게시 된 지침을 사용하고 발표자 당/양식 방식을 사용하고 있습니다. 발표자를 만들 때 SessionFactory에 대한 참조를 유지하고 새 세션을 만들고 세션을 통해 데이터베이스에서 객체를 검색 한 다음 [객체]에 대한 참조를 저장합니다. 폼이 표시되면 해당 필드가 객체에서 채워집니다.
양식을 변경하고 사용자가 데이터를 저장하려면 필드 값에서 개체가 업데이트되고 개체가 데이터베이스에 다시 저장됩니다.
데이터베이스에서 검색 한 시간과 저장 한 시간 사이에 개체가 변경되는 오래된 상태 예외를 처리합니다. 새 세션이 만들어지고 원래 개체가 다시로드되고 사용자에게 갈등이 발생했으며 변경 사항과 현재 데이터베이스에있는 내용이 표시됩니다. 그는 변경 사항을 저장하거나 취소 할 수 있으며 현재 데이터베이스에 저장된 내용을 수락 할 수 있습니다. 제약 조건 위반이 발생할 경우
, 두 가지 중 하나가 일어날 수있는 것으로 보인다 :- 목적은이 새로운 세션으로 다시로드 할 수있는 데이터베이스에 변경되지 않았습니다.
- 개체도 데이터베이스에서 변경되었으며 처음로드 된 개체는 더 이상 반영되지 않습니다.
그러나, 나는 내가 실제로 제약 예외가 (내가 이것을 테스트 한) 발생했기 때문에 부실 상태 예외가 발생하지 않기 때문에 발생하는 경우 감지 할 수 있다고 생각하지 않습니다.
케이스 1은 "FIELD-X에 이미 DB에있는 값이 있습니다"라는 오류 메시지를 표시하고 실제로 아무런 문제가없는 것처럼 가장하기 때문에 취급 사례 1은 간단합니다. 사용자는 FIELD-X를 고유 한 값으로 변경하고 변경 사항을 다시 입력 할 필요없이 다시 저장할 수 있습니다.
처리 사례 2는 일반적인 부실 상태 예외를 처리하는 것과 같습니다.
원본 (또는 그 값)의 복사본을 유지 한 다음 두 필드를 비교하여 "무차별 대입"할 수 있음을 알고 있습니다. 그러나 NHibernate를 활용하여이를 처리하는 더 좋은 방법이 있다고 생각합니다. 어떻게 처리할까요?
경우는 도움이 될 것입니다 :
- 자 NHibernate 버전 : 3.2
- 낙관적 잠금 사용 "더러운"전략
- .NET 프레임 워크 2.0 SP2
- SQLite 데이터베이스/드라이버
2 월 23 일 수정 - 현재 내가하고있는 것을 더 잘 보여주기 위해 몇 가지 예제 코드를 추가했습니다.
/**
* Save handler called when user initiates save in UI.
*
* Returns true when save was successful (essentially, tells the presenter
* that the UI can be closed.
*/
private bool SaveData()
{
try
{
if (this.creatingNewUserAccount)
{
// Do whatever is necessary to instantiate a new object.
this.userAccount = new UserAccount();
// and copy values from the UI into the new object.
this.userAccount.Name = this.form.Name;
// etc.
}
else
{
// Just copy values from the UI into the existing object
// from the database.
this.userAccount.Name = this.form.Name;
// etc.
}
using (ITransaction tx = this.session.BeginTransaction())
{
this.accountRepository.store(this.userAccount);
tx.Commit();
}
return true;
}
catch (StaleObjectStateException)
{
HandleStaleStateException();
return false;
}
catch (ArgumentException e)
{
this.m_View.ShowOtherDialog(e.Message);
return false;
}
catch (GenericADOException e)
{
HandleConstraintViolationException();
return false;
}
}
private void HandleStaleStateException()
{
// The session was trashed when the exception was thrown,
// so close it and create a new one.
this.session.Dispose();
this.session = this.sessionFactory.OpenSession();
CurrentSessionContext.Bind(this.session);
// Reload the object from the database.
this.userAccount = LoadData();
// Do a bunch of things that deal with informing the user
// of the stale-state and displaying a form to merge changes.
HandleEditConflict();
}
private void HandleConstraintViolationException()
{
// The session was trashed when the exception was thrown,
// so close it and create a new one.
this.session.Dispose();
this.session = this.sessionFactory.OpenSession();
CurrentSessionContext.Bind(this.session);
// Determine if trying to save a new entity or editing an existing one.
if (this.creatingNewUserAccount)
{
// If saving a new entity, we don't care about the old object
// we created and tried to save.
this.userAccount = null;
}
else
{
// ????
}
}
내가 의도 한대로 내 코드를 통합했는지는 확실하지 않습니다. 응답 할 때 나는 아무 것도 없었습니다. 코드는 당신을 위해 보냈지 만 - 그러나 이것은 나에게 도움이되지 못했습니다. Lock()은 엔티티를 다시 연결하지 않은 것으로 보이고 Flush()는 DB에 다시 저장하려고 시도합니다. 그러나 Merge()를 사용 하자는 제안은 API를 더 자세히 살펴보고 Refresh()를 찾았습니다. –