我通常擁有的一切設置使用慣例,像這樣以層疊所有:功能NHibernate級聯公約問題 - 刪除的實例傳遞給更新
public class CascadeAllConvention : IHasOneConvention, IHasManyConvention, IReferenceConvention
{
public void Apply(IOneToOneInstance instance)
{
instance.Cascade.All();
}
public void Apply(IOneToManyCollectionInstance instance)
{
instance.Cascade.All();
}
public void Apply(IManyToOneInstance instance)
{
instance.Cascade.All();
}
}
而且使用功能NHibernate自動映射。它通常工作得很好,因爲不必擔心具體的保存命令和類似情況。然而,它的證明是在下列情況下一個問題:
public class QuestionAnswer
{
public CompletedQuestionnaire CompletedQuestionnaire { get; set; }
}
public class CompletedQuestionnaire
{
public long CompletedQuestionnaireId { get; set; }
public IEnumerable<QuestionAnswer> { get; set; }
}
public class Enquiry
{
EnquiryId { get; set; }
CompletedQuestionnaire { get; set; }
}
所以,當我堅持一個新的查詢,所有我在服務方法來保存是具有CompletedQuestionnaire設置和查詢的一個實例進而具有QuestionAnswer實例的集合。那裏沒有問題。
但是,我也想更新這些問題的答案。在這種情況下,查詢和完成問卷需要保持不變。需要發生的是所有問題的答案都被刪除並創建新的答案(因爲該列表的大小會增大或縮小)。
所以服務的方法是:
public CompletedQuestionnaire UpdateCompletedQuestionnaire(CompletedQuestionnaire completedQuestionnaire)
{
var oldCompletedQuestionnaire = _completedQuestionnaireRepository.Single(q => q.CompletedQuestionnaireId == completedQuestionnaire.CompletedQuestionnaireId);
Guard.AgainstEntityLoadException(oldCompletedQuestionnaire, completedQuestionnaire.CompletedQuestionnaireId);
foreach (var oldQuestionAnswer in oldCompletedQuestionnaire.QuestionAnswers)
_questionAnswerRepository.Delete(oldQuestionAnswer);
var answerCount = oldCompletedQuestionnaire.QuestionAnswers.Count();
for (var index = 0; index < answerCount; index++)
((IList<QuestionAnswer>) oldCompletedQuestionnaire.QuestionAnswers).RemoveAt(0);
_completedQuestionnaireRepository.Update(oldCompletedQuestionnaire);
foreach (var newQuestionAnswer in completedQuestionnaire.QuestionAnswers)
{
newQuestionAnswer.CompletedQuestionnaire = oldCompletedQuestionnaire;
_questionAnswerRepository.Add(newQuestionAnswer);
}
UnitOfWork.Commit();
return _completedQuestionnaireRepository.Single(q => q.CompletedQuestionnaireId == completedQuestionnaire.CompletedQuestionnaireId);
}
我從這樣得到的是一個錯誤「刪除的實例傳遞給更新」。我只在NHibernate源代碼中發現了這個異常。如果我嘗試在IOneToManyCollectionInstance上將級聯更改爲All或UpdateAndSave,NHibernate會嘗試將QuestionAnswer記錄的CompletedQuestionnaire外鍵更新爲null,由於不允許使用空值,因此會失敗。如果刪除語句按照代碼順序在此之前運行,這不會成爲問題,但奇怪的是,這不會發生。
還嘗試設置級聯一對多DeleteOrphan,它給出相同的刪除實例通過異常。
上述服務方法實際上是反覆試驗的結果。對於「你做錯了!」的任何見解和解釋,我將不勝感激。
是否可以控制與NHiberante執行的語句的順序。說一個像DeleteBeforeUpdate或類似的慣例?
編輯:我已經修改了服務方法:
public CompletedQuestionnaire UpdateCompletedQuestionnaire(long completedQuestionnaireId, IEnumerable<QuestionAnswer> newAnswers)
{
var completedQuestionnaire = _completedQuestionnaireRepository.Single(q => q.CompletedQuestionnaireId == completedQuestionnaireId);
Guard.AgainstEntityLoadException(completedQuestionnaire, completedQuestionnaireId);
((IList<QuestionAnswer>)completedQuestionnaire.QuestionAnswers).Clear();
foreach (var newAnswer in newAnswers)
{
newAnswer.CompletedQuestionnaire = completedQuestionnaire;
_questionAnswerRepository.Add(newAnswer);
}
_completedQuestionnaireRepository.Update(completedQuestionnaire);
UnitOfWork.Commit();
return completedQuestionnaire;
}
而改變相關級聯公約:
public void Apply(IOneToManyCollectionInstance instance)
{
instance.Cascade.AllDeleteOrphan();
}
現在我得到異常「刪除對象將被重新保存通過級聯(從關聯中刪除已刪除的對象)「。如何正確地從關聯中刪除對象?