Duplicate Record Protection
When I check my next branch in to trunk it will include code template changes that handle duplicate record exceptions (ConstraintException). This exception occurs if you edit a record so that it has the same primary key as an existing record. At present, if you do this, Open Petra will generate an unhandled exception error and show you the unfriendly exception screen. With the code change outlined here, the duplicate record exception will generate one of our standard Validation Error messages and you will not be able to move away from the current record until you fix the problem.
When you see the error message it will contain helpful information about the details that are causing the constraint exception.
All the code for this is contained in the generated code. There is no manual coding required.
However, the changes will need some testing and I will need some help from you to do this. This post describes how to do the testing and the screens that are affected.
Altogether 11 templates have been modified to trap the ConstraintException caused when ARow.EndEdit() is called. Of these eleven templates, five are not used in a context where EndEdit() is actually called – that is to say the templates are used in a context that is not associated with a Details Panel. But it is possible that one day they might be, so the template code has been written with this possibility in mind. For now though, these five templates, which are the basis of 31 screens/controls, should produce the same code that they have always produced for the screens that use them. I have checked that this is so.
That leaves six templates where there is now new code being generated. Altogether these six templates are used to generate 94 screens where duplicate record exceptions will now be trapped. We really need to test these 94 screens, although many of them are essentially similar (and very simple) so the testing will be very quick.
The test involves clicking the ‘New’ button twice to get two new rows; then editing the second row so that (at least) its primary key element(s) are the same. Finally, click the ‘New’ button again and check that a message box appears with the correct text and ‘help’. The help should be something like:
A row already exists for the key value of ‘GBP’
or
A row already exists for the key combination of ‘GBP’ + ‘NEWCODE1’
If you get a message like:
A row already exists using the values that you have entered
or
A row already exists for the key combination of ‘GBP’ + ‘?’
that constitutes an error that should be reported, because we always want to be able to report something – and a question mark means we could not work it out for that screen.
The user is only alerted to fields which can be edited on that screen. So if there is a part of the primary key that is implied by the screen itself and the user does not edit it, it won’t be part of the help text. For example, if the ledger number is the first element of the primary key but the screen is for that specific ledger number you won’t see any reference to ledger number in the ‘help’ text. This is by design.
In addition to trapping duplicate record errors the new code also deals with the case where the user cursors down through the list of entries in a grid. At present this is recorded as a ‘edit’ in the database – that is to say that you as the current logged-in user have edited every record you scroll through. This was never the intention. As a result of this checkin you will only be recorded as having edited a record that you actually change.
Let me summarise the key points again.
There are 33 screens which have a new template,, but the generated code is identical to what we had before.
There are 92 screens where the code will be different. In all these cases we will no longer record cursor-ing through a row as an edit. Also, all the time you do what you do normally, you will not create a constraint exception so the screen should function exactly as before. Only when you edit a new row to match an existing record will you see the new functionality. When this happens we need to check that the message help correctly identifies the bad input.
Here is a list of the screens that need to be tested
SCREENS WITH DETAILS
WindowEdit (6)
MFinance\Gui\Budget\MaintainBudget-generated.cs(668):// :WE:GetDetailsFromControls
MFinance\Gui\Setup\GiftMotivationSetup-generated.cs(726):// :WE:GetDetailsFromControls
MFinance\Gui\Setup\MotivationGroupSetup-generated.cs(647):// :WE:GetDetailsFromControls
MFinance\Gui\Setup\SetupAnalysisTypes-generated.cs(639):// :WE:GetDetailsFromControls
MPartner\Gui\PersonnelStaffData-generated.cs(760):// :WE:GetDetailsFromControls
MSysMan\Gui\MaintainUsers-generated.cs(633):// :WE:GetDetailsFromControls
WindowTDS (2)
MFinance\Gui\Setup\GLAccountHierarchy-generated.cs(383):// :WTDS:GetDataFromControls
MFinance\Gui\Setup\GLCostCentreHierarchy-generated.cs(256):// :WTDS:GetDataFromControls
WindowMaintainTable (10)
MCommon\Gui\Setup\InternationalPostalTypeSetup-generated.cs(704):// :WMT:GetDetailsFromControls
MCommon\Gui\Setup\SetupCurrency-generated.cs(738):// :WMT:GetDetailsFromControls
MFinance\Gui\Setup\CurrencyLanguageSetup-generated.cs(882):// :WMT:GetDetailsFromControls
MFinance\Gui\Setup\SetupAdminGrantsPayable-generated.cs(840):// :WMT:GetDetailsFromControls
MFinance\Gui\Setup\SetupAdminGrantsReceivable-generated.cs(840):// :WMT:GetDetailsFromControls
MFinance\Gui\Setup\SetupCorporateExchangeRate-generated.cs(727):// :WMT:GetDetailsFromControls
MFinance\Gui\Setup\SetupDailyExchangeRate-generated.cs(731):// :WMT:GetDetailsFromControls
MPartner\Gui\Setup\MailingSetup-generated.cs(768):// :WMT:GetDetailsFromControls
MPersonnel\Gui\Setup\ApplicationTypeSetup-generated.cs(838):// :WMT:GetDetailsFromControls
MSysMan\Gui\Setup\SecurityGroupSetup-generated.cs(685):// :WMT:GetDetailsFromControls
WindowMaintainCacheableTable (51)
MCommon\Gui\Setup\CountrySetup-generated.cs(473):// :WMCT:GetDetailsFromControls
MCommon\Gui\Setup\FrequencySetup-generated.cs(429):// :WMCT:GetDetailsFromControls
MCommon\Gui\Setup\LanguageCodeSetup-generated.cs(425):// :WMCT:GetDetailsFromControls
MCommon\Gui\Setup\LocalDataFieldSetup-generated.cs(452):// :WMCT:GetDetailsFromControls
MConference\Gui\Setup\ConferenceCostTypeSetup-generated.cs(434):// :WMCT:GetDetailsFromControls
MFinance\Gui\Setup\EmailDestinationSetup-generated.cs(420):// :WMCT:GetDetailsFromControls
MFinance\Gui\Setup\SetupCostCentreTypes-generated.cs(412):// :WMCT:GetDetailsFromControls
MFinance\Gui\Setup\SetupMethodOfGiving-generated.cs(449):// :WMCT:GetDetailsFromControls
MFinance\Gui\Setup\SetupMethodOfPayment-generated.cs(424):// :WMCT:GetDetailsFromControls
MPartner\Gui\Setup\AcquisitionCodeSetup-generated.cs(437):// :WMCT:GetDetailsFromControls
MPartner\Gui\Setup\AddresseeTypeSetup-generated.cs(413):// :WMCT:GetDetailsFromControls
MPartner\Gui\Setup\BusinessCodeSetup-generated.cs(413):// :WMCT:GetDetailsFromControls
MPartner\Gui\Setup\ContactAttributeSetup-generated.cs(419):// :WMCT:GetDetailsFromControls
MPartner\Gui\Setup\ContactMethodSetup-generated.cs(433):// :WMCT:GetDetailsFromControls
MPartner\Gui\Setup\DenominationCodeSetup-generated.cs(425):// :WMCT:GetDetailsFromControls
MPartner\Gui\Setup\InterestCategorySetup-generated.cs(420):// :WMCT:GetDetailsFromControls
MPartner\Gui\Setup\InterestSetup-generated.cs(408):// :WMCT:GetDetailsFromControls
MPartner\Gui\Setup\LocalDataOptionListNameSetup-generated.cs(401):// :WMCT:GetDetailsFromControls
MPartner\Gui\Setup\LocalDataOptionsSetup-generated.cs(422):// :WMCT:GetDetailsFromControls
MPartner\Gui\Setup\LocationTypeSetup-generated.cs(421):// :WMCT:GetDetailsFromControls
MPartner\Gui\Setup\MaritalStatusSetup-generated.cs(432):// :WMCT:GetDetailsFromControls
MPartner\Gui\Setup\OccupationCodeSetup-generated.cs(425):// :WMCT:GetDetailsFromControls
MPartner\Gui\Setup\PartnerStatusSetup-generated.cs(437):// :WMCT:GetDetailsFromControls
MPartner\Gui\Setup\PartnerTypeSetup-generated.cs(425):// :WMCT:GetDetailsFromControls
MPartner\Gui\Setup\PublicationCostSetup-generated.cs(422):// :WMCT:GetDetailsFromControls
MPartner\Gui\Setup\PublicationSetup-generated.cs(443):// :WMCT:GetDetailsFromControls
MPartner\Gui\Setup\ReasonSubscriptionCancelledSetup-generated.cs(401):// :WMCT:GetDetailsFromControls
MPartner\Gui\Setup\ReasonSubscriptionGivenSetup-generated.cs(401):// :WMCT:GetDetailsFromControls
MPartner\Gui\Setup\RelationCategorySetup-generated.cs(432):// :WMCT:GetDetailsFromControls
MPartner\Gui\Setup\RelationshipSetup-generated.cs(441):// :WMCT:GetDetailsFromControls
MPersonnel\Gui\Setup\AbilityAreaSetup-generated.cs(432):// :WMCT:GetDetailsFromControls
MPersonnel\Gui\Setup\AbilityLevelSetup-generated.cs(431):// :WMCT:GetDetailsFromControls
MPersonnel\Gui\Setup\ApplicantStatusSetup-generated.cs(432):// :WMCT:GetDetailsFromControls
MPersonnel\Gui\Setup\ArrivalDeparturePointSetup-generated.cs(432):// :WMCT:GetDetailsFromControls
MPersonnel\Gui\Setup\Country_EventLevelSetup-generated.cs(432):// :WMCT:GetDetailsFromControls
MPersonnel\Gui\Setup\DocumentTypeCategorySetup-generated.cs(432):// :WMCT:GetDetailsFromControls
MPersonnel\Gui\Setup\DocumentTypeSetup-generated.cs(440):// :WMCT:GetDetailsFromControls
MPersonnel\Gui\Setup\DriverStatusSetup-generated.cs(432):// :WMCT:GetDetailsFromControls
MPersonnel\Gui\Setup\EventRoleSetup-generated.cs(493):// :WMCT:GetDetailsFromControls
MPersonnel\Gui\Setup\JobAssignmentTypeSetup-generated.cs(433):// :WMCT:GetDetailsFromControls
MPersonnel\Gui\Setup\LanguageLevelSetup-generated.cs(439):// :WMCT:GetDetailsFromControls
MPersonnel\Gui\Setup\LeadershipRatingSetup-generated.cs(432):// :WMCT:GetDetailsFromControls
MPersonnel\Gui\Setup\LeavingCodeSetup-generated.cs(432):// :WMCT:GetDetailsFromControls
MPersonnel\Gui\Setup\OrganisationContactSetup-generated.cs(432):// :WMCT:GetDetailsFromControls
MPersonnel\Gui\Setup\PassportTypeSetup-generated.cs(432):// :WMCT:GetDetailsFromControls
MPersonnel\Gui\Setup\PositionSetup-generated.cs(432):// :WMCT:GetDetailsFromControls
MPersonnel\Gui\Setup\ProfessionalAreaSetup-generated.cs(432):// :WMCT:GetDetailsFromControls
MPersonnel\Gui\Setup\QualificationLevelSetup-generated.cs(431):// :WMCT:GetDetailsFromControls
MPersonnel\Gui\Setup\SkillCategorySetup-generated.cs(432):// :WMCT:GetDetailsFromControls
MPersonnel\Gui\Setup\SkillLevelSetup-generated.cs(431):// :WMCT:GetDetailsFromControls
MSysMan\Gui\Setup\LanguageSpecificSetup-generated.cs(567):// :WMCT:GetDetailsFromControls
ControlMaintainTable (24)
MFinance\Gui\Gift\UC_GiftBatches-generated.cs(856):// :CMT:GetDetailsFromControls
MFinance\Gui\Gift\UC_GiftTransactions-generated.cs(967):// :CMT:GetDetailsFromControls
MFinance\Gui\Gift\UC_RecurringGiftBatches-generated.cs(798):// :CMT:GetDetailsFromControls
MFinance\Gui\Gift\UC_RecurringGiftTransactions-generated.cs(1049):// :CMT:GetDetailsFromControls
MFinance\Gui\Setup\UC_AccountAnalysisAttributes-generated.cs(649):// :CMT:GetDetailsFromControls
MFinance\Gui\Setup\UC_SetupAnalysisValues-generated.cs(651):// :CMT:GetDetailsFromControls
MFinance\Gui\GL\UC_GLAttributes-generated.cs(626):// :CMT:GetDetailsFromControls
MFinance\Gui\GL\UC_GLBatches-generated.cs(705):// :CMT:GetDetailsFromControls
MFinance\Gui\GL\UC_GLJournals-generated.cs(700):// :CMT:GetDetailsFromControls
MFinance\Gui\GL\UC_GLTransactions-generated.cs(752):// :CMT:GetDetailsFromControls
MPartner\Gui\UC_Applications-generated.cs(536):// :CMT:GetDetailsFromControls
MPartner\Gui\UC_IndividualData_Abilities-generated.cs(716):// :CMT:GetDetailsFromControls
MPartner\Gui\UC_IndividualData_CommitmentPeriods-generated.cs(767):// :CMT:GetDetailsFromControls
MPartner\Gui\UC_IndividualData_JobAssignments-generated.cs(750):// :CMT:GetDetailsFromControls
MPartner\Gui\UC_IndividualData_Passport-generated.cs(831):// :CMT:GetDetailsFromControls
MPartner\Gui\UC_IndividualData_PersonalDocuments-generated.cs(818):// :CMT:GetDetailsFromControls
MPartner\Gui\UC_IndividualData_PersonalLanguages-generated.cs(712):// :CMT:GetDetailsFromControls
MPartner\Gui\UC_IndividualData_PersonSkills-generated.cs(933):// :CMT:GetDetailsFromControls
MPartner\Gui\UC_IndividualData_PreviousExperience-generated.cs(768):// :CMT:GetDetailsFromControls
MPartner\Gui\UC_IndividualData_ProgressReports-generated.cs(731):// :CMT:GetDetailsFromControls
MPartner\Gui\UC_PartnerRelationships-generated.cs(676):// :CMT:GetDetailsFromControls
MPartner\Gui\UC_Subscriptions-generated.cs(602):// :CMT:GetDetailsFromControls
MPartner\Gui\Extracts\UC_ExtractMaintain-generated.cs(621):// :CMT:GetDetailsFromControls
MPartner\Gui\Extracts\UC_ExtractMasterList-generated.cs(753):// :CMT:GetDetailsFromControls
ControlMaintainCacheableTable (1)
MPartner\Gui\Setup\UC_ContactAttributeDetail-generated.cs(383):// :CMCT:GetDetailsFromControls
These screens are generated from templates that have been changed but do not generate any new code
SCREENS WITH NO DETAILS
Window (5) Already checked by Alan
MFinance\Gui\AP\APAnalysisAttributes-generated.cs(149):// :W:GetDataFromControls
MFinance\Gui\AP\APPayment-generated.cs(259):// :W:GetDataFromControls
MPartner\Gui\Extracts\ExtractMaster-generated.cs(229):// :W:ucValidation
MPartner\Gui\Extracts\UpdateExtractAddSubscriptionDialog-generated.cs(147):// :W:GetDataFromControls
app\MainWindow\MainWindow-generated.cs(163):// :W:ucValidation
WindowFind (5) Checked
MConference\Gui\ConferenceFindForm-generated.cs(174):// :WF:GetDataFromControls
MPartner\Gui\PartnerContacts-generated.cs(220):// :WF:GetDataFromControls
MPartner\Gui\PartnerFind-generated.cs(222):// :WF:ucValidation
MFinance\Gui\AP\APMain-generated.cs(222):// :WF:ControlToValidate
MFinance\Gui\AP\APSupplierTransactions-generated.cs(216):// :WF:GetDataFromControls
WindowEditUIConnector (2) Already checked by Alan
MPartner\Gui\PartnerEdit-generated.cs(230):// :WEUIC:GetDataFromControls
MFinance\Gui\AP\APEditSupplier-generated.cs(387):// :WEUIC:GetDataFromControls
WindowEditWebConnectorMasterDetail (1) Already checked by Alan
MFinance\Gui\AP\APEditDocument-generated.cs(917):// :WEWCMD:GetDataFromControls
WindowTDS (3) Already checked by Alan
MFinance\Gui\Gift\GiftBatch-generated.cs(177):// :WTDS:GetDataFromControls
MFinance\Gui\Gift\RecurringGiftBatch-generated.cs(177):// :WTDS:GetDataFromControls
MFinance\Gui\GL\GLBatch-generated.cs(195):// :WTDS:GetDataFromControls
UserControl (15) Already checked by Alan
MPartner\Gui\UC_ApplicationPage_Applicant_Event-generated.cs(374):// :UC:GetDataFromControls
MPartner\Gui\UC_ApplicationPage_Event-generated.cs(284):// :UC:GetDataFromControls
MPartner\Gui\UC_ApplicationPage_Travel-generated.cs(544):// :UC:GetDataFromControls
MPartner\Gui\UC_IndividualData_EmergencyData-generated.cs(322):// :UC:GetDataFromControls
MPartner\Gui\UC_IndividualData_PersonalData-generated.cs(223):// :UC:GetDataFromControls
MPartner\Gui\UC_IndividualData_Summary-generated.cs(424):// :UC:GetDataFromControls
MPartner\Gui\UC_PartnerDetails_Bank-generated.cs(314):// :UC:GetDataFromControls
MPartner\Gui\UC_PartnerDetails_Church-generated.cs(401):// :UC:GetDataFromControls
MPartner\Gui\UC_PartnerDetails_Family-generated.cs(310):// :UC:GetDataFromControls
MPartner\Gui\UC_PartnerDetails_Organisation-generated.cs(342):// :UC:GetDataFromControls
MPartner\Gui\UC_PartnerDetails_Person-generated.cs(358):// :UC:GetDataFromControls
MPartner\Gui\UC_PartnerDetails_Unit-generated.cs(325):// :UC:GetDataFromControls
MPartner\Gui\UC_PartnerDetails_Venue-generated.cs(310):// :UC:GetDataFromControls
MPartner\Gui\UC_PartnerEdit_TopPart-generated.cs(628):// :UC:GetDataFromControls
MPartner\Gui\UC_Subscription-generated.cs(392):// :UC:GetDataFromControls