====== CRUD ====== **CRUD** is a [[SOLoist Sample Applications|SOLoist sample application]], a simple demo of a classical [[wp>Create,_read,_update_and_delete | CRUD]] (Create, Read, Update, Delete) pattern for objects of a class. The left-hand list box renders all objects of the class //Person//. When one is selected, its //Bank Accounts// are listed in the list box in the middle. When a Bank Account is selected, its slots can be edited in the slot editors on the right. A new Bank Account can be created, or an existing one can be deleted with the generic commands (the buttons at the bottom). When a slot of a Bank Accoount is modified, as soon as its control loses its focus, the SOLoist notification mechanism updates all its manifestations on the page (try, for example, to change the number of an existing Bank Account and watch it in the list). ==== Live example ==== [[http://soloistdemo.org/SampleApplications/personsandbankaccounts.html]]\\ [[http://soloistdemo.org/SampleApplications/oql?q=SELECT+p%2C+p.name%2C+p.gender%2C+p.age%2C+p.dateOfBirth%2C+p.height%2C+p.isMarried%2C+p.photo%2C+p.rootFolder%0D%0AFROM+Person+p&f=html | OQL Query: Persons]]\\ [[http://soloistdemo.org/SampleApplications/oql?q=SELECT+b%2C+b.number%2C+b.amount%2C+b.bankName%2C+b.owner%0AFROM+BankAccount+b&hide=0 | OQL Query: Bank Accounts]] |{{screen:personsandbankaccounts.png?350}}| ===== UML Model ===== {{personsandbankaccounts.png}} ===== Business Logic Code ===== public void execute() // ------------- // ------------- { // --------- Person p = person.val(); if (p == null) { throw new CommandPreconditionsException("Please, select person first."); } BankAccount ba = new BankAccount(); ba.number.set(Text.fromString("xxx-xxx-xxx")); ba.amount.set(Currency.fromBigDecimal(BigDecimal.valueOf(0.))); ba.bankName.set(Text.fromString("New Bank")); p.accounts.add(ba); // --------- } ===== GUI Code ===== package rs.sol.sampleapps; import rs.sol.sampleapps.commands.CreateAccountForPerson; import rs.sol.soloist.helpers.init.DefaultContextInit; import rs.sol.soloist.helpers.init.Initializer; import rs.sol.soloist.helpers.init.InitializerFailedException; import rs.sol.soloist.server.builtindomains.builtincommands.CmdDestroyObject; import rs.sol.soloist.server.guiconfiguration.components.GUIApplicationComponent; import rs.sol.soloist.server.guiconfiguration.components.GUIButtonComponent; import rs.sol.soloist.server.guiconfiguration.components.GUILabelComponent; import rs.sol.soloist.server.guiconfiguration.components.GUIPanelComponent; import rs.sol.soloist.server.guiconfiguration.construction.GUIComponentBinding; import rs.sol.soloist.server.guiconfiguration.elementcomponents.GUIEdit; import rs.sol.soloist.server.guiconfiguration.elementcomponents.GUIInput; import rs.sol.soloist.server.guiconfiguration.layout.TableLayoutData; import rs.sol.soloist.server.guiconfiguration.layout.VerticalAlignment; import rs.sol.soloist.server.guiconfiguration.nonvisualcompoments.GUIFindAllInstancesSAPComponent; import rs.sol.soloist.server.guiconfiguration.style.GUIContext; import rs.sol.soloist.server.guiconfiguration.style.GUINumberTextFeature; import rs.sol.soloist.server.guiconfiguration.style.GUIObjectSetting; import rs.sol.soloist.server.guiconfiguration.style.GUIPictureFeature; import rs.sol.soloist.server.guiconfiguration.style.GUITextFeature; import rs.sol.soloist.server.server.SoloistServiceServlet; public enum PersonsAndBankAccounts implements Initializer{ INSTANCE; @Override public void init() throws InitializerFailedException { GUIApplicationComponent page = new GUIApplicationComponent(); // new web page page.setName("PersonsAndBankAccounts"); SoloistServiceServlet.registerApplication(page); GUIContext context = createContextAndStyles(); page.setContext(context); GUIPanelComponent root = GUIPanelComponent.createFlow(page); GUILabelComponent title = GUILabelComponent.create(root, "Persons and Bank Accounts"); title.setStyle("titleStyle"); GUIPanelComponent topPanel = GUIPanelComponent.createFlow(root); topPanel.setStyle("topPanel"); GUIPanelComponent table = GUIPanelComponent.createTable(topPanel); // first row GUILabelComponent.create(table, "Persons", 0, 0); GUILabelComponent.create(table, "Person's Bank Accounts", 0, 1); GUILabelComponent.create(table, "Account Details", 0, 2); // second row // this component fetches all persons, it is invisible component but still, it has to have a parent GUIFindAllInstancesSAPComponent allPersons = GUIFindAllInstancesSAPComponent.create(root, Person.CLASSIFIER); GUIInput personsList = GUIInput.createList(table); personsList.setLayoutData(TableLayoutData.create(1, 0)); // shows all persons GUIComponentBinding.create(allPersons.opValue(), personsList.ipCollection()); personsList.setSize("250px", "300px"); personsList.setStyle("listWidget"); GUIInput accountsList = GUIInput.createList(table, Person.PROPERTIES.accounts); accountsList.setLayoutData(TableLayoutData.create(1, 1)); accountsList.setSize("250px", "300px"); accountsList.setStyle("listWidget"); GUIPanelComponent accountDetailsTable = GUIPanelComponent.createTable(table); accountDetailsTable.setRowColumn(1, 2); // place the accountDetailsTable accountDetailsTable.setCellAlignment(null, VerticalAlignment.TOP); // third row GUIButtonComponent createAccountButton = GUIButtonComponent.create(table, "Create Account for Person", new CreateAccountForPerson()); createAccountButton.setLayoutData(TableLayoutData.create(2, 0)); CmdDestroyObject destroyCmd = new CmdDestroyObject(); destroyCmd.setType(BankAccount.CLASSIFIER); GUIButtonComponent destroyAccountButton = GUIButtonComponent.create(table, "Delete Account", destroyCmd); destroyAccountButton.setLayoutData(TableLayoutData.create(2, 1)); // let's fill in the accoutDetailsTable GUILabelComponent.create(accountDetailsTable, "Number:", 0, 0); GUILabelComponent.create(accountDetailsTable, "Amount:", 1, 0); GUILabelComponent.create(accountDetailsTable, "Bank name:", 2, 0); GUIEdit numberEditor = GUIEdit.createField(accountDetailsTable, BankAccount.PROPERTIES.number, 0, 1); GUIEdit amountEditor = GUIEdit.createField(accountDetailsTable, BankAccount.PROPERTIES.amount, 1, 1); GUIEdit bankNameEditor = GUIEdit.createField(accountDetailsTable, BankAccount.PROPERTIES.bankName, 2, 1); // let's bind the components // account list will be populated for the selected person in the persons list GUIComponentBinding.create(personsList.opValue(), accountsList.ipSlotValueElement()); // this specifies that account will be created for selected person GUIComponentBinding.create(personsList.opValue(), createAccountButton, CreateAccountForPerson.PROPERTIES.person); // this specifies that selected account will be destroyed GUIComponentBinding.create(accountsList.opValue(), destroyAccountButton, CmdDestroyObject.PROPERTIES.input); GUIComponentBinding.create(accountsList.opValue(), numberEditor.ipElement()); GUIComponentBinding.create(accountsList.opValue(), amountEditor.ipElement()); GUIComponentBinding.create(accountsList.opValue(), bankNameEditor.ipElement()); } private GUIContext createContextAndStyles() { GUIContext context = new GUIContext(); DefaultContextInit.getRoot().addContext(context); GUIObjectSetting bankAccount = GUIObjectSetting.create(context, BankAccount.CLASSIFIER); GUITextFeature.createName(bankAccount, BankAccount.PROPERTIES.number); GUITextFeature.createFixedSeparator(bankAccount, "/"); GUINumberTextFeature.createDescription(bankAccount, BankAccount.PROPERTIES.amount); GUIPictureFeature.createSmallIcon(bankAccount, "images/icons/bankaccount.png"); GUIObjectSetting person = GUIObjectSetting.create(context, Person.CLASSIFIER); GUITextFeature.createName(person, Person.PROPERTIES.name); GUITextFeature.createFixedSeparator(person, "Age:"); GUITextFeature.createDescription(person, Person.PROPERTIES.age); GUIPictureFeature.createSmallIcon(person, "images/icons/person.png"); return context; } }