Can someone share some sample codes on how to set the value of a non-editable Combobox? It is similar to this, but when I tried to insert it in my code. It returns a null value
Code
ObservableList<City> data = FXCollections.observableArrayList();
data = AddressGetWay.getCityByProvince("Batanes")
cmbCity.setItems(data); // set the items from the database
cmbCity.setConverter(new StringConverter<City>() {
#Override
public String toString(City object) {
return object.getCityName();
}
#Override
public City fromString(String string) {
return cmbCity.getItems().stream().filter(ap
-> ap.getCityName().equals(string)).findFirst().orElse(null);
}
});
cmbCity.valueProperty().addListener(
(ObservableValue<? extends City> observable, City oldValue, City newVal) -> {
if (newVal != null) {
//
}
}
);
// TODO: get the data stored in the database (Column City)
// and set the value of the ComboBox.
Predicate<City> predicate = city -> city.getCityName() == "Itbayat"; // Let's assume that the data stored in the database is "Itbayat"
Optional<City> opt = data.stream().filter(predicate).findAny();
cmbCity.getSelectionModel().select(opt.orElse(null)); // the ComboBox value should be "Itbayat".
I'm using a Singleton Class (correct me if I'm wrong) to retrieve the data from the database
public class AddressGetWay {
static Connection con; //connect to the database
static PreparedStatement pst = null;
static ResultSet rs = null;
public static ObservableList<City> getCityByProvince(String prov) {
ObservableList<City> listData = FXCollections.observableArrayList();
String sql = "SELECT pk_cit_id, cit_nm, zip_code FROM city_mun WHERE prov_code = (SELECT prov_code FROM provinces WHERE prov_nm = ?)";
try {
pst = con.prepareStatement(sql);
pst.setString(1, prov);
rs = pst.executeQuery();
while (rs.next()) {
listData.add(new City(
rs.getInt(1),
rs.getString(2),
rs.getInt(3)
));
}
} catch (SQLException ex) {
Logger.getLogger(AddressGetWay.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
pst.close();
rs.close();
} catch (SQLException ex) {
Logger.getLogger(AddressGetWay.class.getName()).log(Level.SEVERE, null, ex);
}
}
return listData;
}
}
This should be my desired Output
But I got this output using the above code
As for my naming conventions. I tried to do this if there's something I need to correct, feel free to pinpoint.
It seems that you are having issue on this code block,
ObservableList<City> data = AddressGetWay.getCityByProvince("Batanes");
//....
Predicate<City> predicate = city -> city.getCityName() == "Itbayat";
Optional<City> opt = data.stream().filter(predicate).findAny();
cmbCity.getSelectionModel().select(opt.orElse(null));
I suspect some loop-holes that is overcoming the null-value.
As you retrieving data through province Batanes i.e. ObservableList<City> data = AddressGetWay.getCityByProvince("Batanes"), maybe it's not retrieving any data.
Your predicate is comparing cityName Itbayat, which may not be getting matched with the retrieved data.
Please check the database value for the city table as to compare those data as well
AddressGateWay
public class AddressGateWay {
private static Connection connection;
private static PreparedStatement statement = null;
private static ResultSet result = null;
static {
connection = loadConnection();
}
public static ObservableList<City> getCityByProvince(String prov) {
ObservableList<City> listData = FXCollections.observableArrayList();
String sql = "SELECT pk_cit_id, cit_nm, zip_code FROM city_mun WHERE prov_code = (SELECT prov_code FROM provinces WHERE prov_nm = ?)";
try {
statement = connection.prepareStatement(sql);
statement.setString(1, prov);
result = statement.executeQuery();
while (result.next()) {
listData.add(new City(
result.getInt(1),
result.getString(2)
));
}
} catch (SQLException ex) {
Logger.getLogger(AddressGateWay.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
statement.close();
result.close();
} catch (SQLException ex) {
Logger.getLogger(AddressGateWay.class.getName()).log(Level.SEVERE, null, ex);
}
}
return listData;
}
// for editing
public static ObservableList<Address> selectedItem(int item) {
ObservableList<Address> listData = FXCollections.observableArrayList();
String sql = "SELECT prov_nm, city_nm FROM emp_address WHERE pk_address_id = ?";
try {
statement = connection.prepareStatement(sql);
statement.setString(1, item);
result = statement.executeQuery();
if (result.next()) {
listData.add(new Address(
result.getString(1),
result.getString(2)
));
}
} catch (SQLException ex) {
Logger.getLogger(AddressGateWay.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
statement.close();
result.close();
} catch (SQLException ex) {
Logger.getLogger(AddressGateWay.class.getName()).log(Level.SEVERE, null, ex);
}
}
return listData;
}
}
City
public class City {
private int id;
private String cityName;
public City(int id, String cityName) {
this.id = id;
this.cityName = cityName;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCityName() {
return cityName;
}
public void setCityName(String cityName) {
this.cityName = cityName;
}
}
Controller Logic Code
ObservableList<City> cities = AddressGateWay.getCityByProvince(provinceComboBox.getValue()); // assume the value is "Batanes"
cityComboBox.setItems(cities);
cityComboBox.setConverter(new StringConverter<City>() {
#Override
public String toString(City object) {
return object.getCityName();
}
#Override
public City fromString(String string) {
return cityComboBox.getItems().stream().filter(ap
-> ap.getCityName().equals(string)).findFirst().orElse(null);
}
});
cityComboBox.valueProperty().addListener(
(ObservableValue<? extends City> observable, City oldValue, City newVal) -> {
if (newVal != null) {
//
}
}
);
City city = cities
.stream()
.filter(c -> c.getCityName() == "Itbayat")
.findAny()
.orElse(null);
cityComboBox.getSelectionModel().select(city);
// summing up the below updates and your codes,
// I have set the value of cityComboBox by using . . .
Address ads = new Address();
ads = AddressGetWay.selectedItem(item); // the item to be edit
// assume the value from the database is "Itbayat"
Predicate<City> predicate = city -> city.getCityName() == ads.getCity().getCityName();
Optional<City> opt = cities.stream().filter(predicate).findAny();
cityComboBox.getSelectionModel().select(opt.orElse(null));
// Thank you, it finally work :)
Some key points based on the updated code
Refactoring code based on unnecessary code
Implementing basic Java naming Conventions
Missing connection initialization (need to load based on your database)
Inined code (for Predicate, and Optional)
EDIT
Province
public class Province {
private String provinceCode;
private String provinceName;
//Constructors
//Getters and Setters
}
Address
public class Address {
private City city;
private Province province;
//Constructors
//Getters and Setters
}
Related
I am trying to get list of Tbcompany table using Transformers.aliasToBean with 2 primary key fields.
I am using SQL SERVER and Hibernate 3.2.4.
My table has 2 primary fields.
Tbcompany.class
public class Tbcompany {
private TbcompanyId id;
private String hcompanycode;
public TbcompanyId getId() {
return id;
}
public void setId(TbcompanyId id) {
this.id = id;
}
public String getHcompanycode() {
return hcompanycode;
}
public void setHcompanycode(String hcompanycode) {
this.hcompanycode = hcompanycode;
}
}
And inside TbcompanyId.class :
public class TbcompanyId
implements Serializable
{
private String companycode;
private String companyname;
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof TbcompanyId)) {
return false;
}
TbcompanyId other = ((TbcompanyId) o);
if (this.companycode == null) {
if (other.companycode!= null) {
return false;
}
} else {
if (!this.companycode.equals(other.companycode)) {
return false;
}
}
if (this.companyname == null) {
if (other.companyname!= null) {
return false;
}
} else {
if (!this.companyname.equals(other.companyname)) {
return false;
}
}
return true;
}
public int hashCode() {
int rtn = 17;
rtn = (rtn* 37);
if (this.companycode!= null) {
rtn = (rtn + this.companycode.hashCode());
}
rtn = (rtn* 37);
if (this.companyname!= null) {
rtn = (rtn + this.companyname.hashCode());
}
return rtn;
}
public String getCompanycode() {
return companycode;
}
public void setCompanycode(String companycode) {
this.companycode = companycode;
}
public String getCompanyname() {
return companyname;
}
public void setCompanyname(String companyname) {
this.companyname = companyname;
}
I want to create a form and use Transformers.aliasToBean to populate the form .
This query :
Query q;
q = session.createQuery("SELECT a.id.companycode as companycode,a.id.companyname as companyname,a.hcompanycode as hcompanycode FROM Tbcompany a");
q.setResultTransformer(Transformers.aliasToBean(Tbcompany.class));
list = q.list();
gives me an error of :
org.hibernate.PropertyNotFoundException: Could not find setter for companycode on class com.loansdb.data.Tbcompany
While this query :
Query q;
q = session.createQuery("SELECT a.id.companycode,a.id.companyname,a.hcompanycode as hcompanycode FROM
Tbcompany a");
q.setResultTransformer(Transformers.aliasToBean(Tbcompany.class));
list = q.list();
gives me this error :
org.hibernate.PropertyNotFoundException: Could not find setter for 0 on class com.loansdb.data.Tbcompany
Does anyone know how to do this?
The aliasToBean transformer use the name of the SQL columns returned and try to find a field with the same name on the class target that have a set method created.
So, your query returns a a.id.companycode:
SELECT a.id.companycode as companycode,a.id.companyname as companyname,a.hcompanycode as hcompanycode FROM Tbcompany a
The error said:
org.hibernate.PropertyNotFoundException: Could not find setter for companycode on class com.loansdb.data.Tbcompany
And your Tbcompany class does not have a setter to companycode.
So, to correct your Tbcompany class and looking your query, seems to me that the class it's something like:
public class Tbcompany {
private String companycode;
private String companycode;
private String companyname;
public String setCompanycode(String companycode) {
this.companycode = companycode;
}
// create the constructor, getters and setters
}
I am trying to access GAE Memcache and Datastore APIs from Dataflow.
I have followed How to use memcache in dataflow? and setup Remote API https://cloud.google.com/appengine/docs/java/tools/remoteapi
In my pipeline I have written
public static void main(String[] args) throws IOException {
RemoteApiOptions remApiOpts = new RemoteApiOptions()
.server("xxx.appspot.com", 443)
.useApplicationDefaultCredential();
RemoteApiInstaller installer = new RemoteApiInstaller();
installer.install(remApiOpts);
try {
DatastoreConfigManager2.registerConfig("myconfig");
final String topic = DatastoreConfigManager2.getString("pubsub.topic");
final String stagingDir = DatastoreConfigManager2.getString("dataflow.staging");
...
bqRows.apply(BigQueryIO.Write
.named("Insert row")
.to(new SerializableFunction<BoundedWindow, String>() {
#Override
public String apply(BoundedWindow window) {
// The cast below is safe because CalendarWindows.days(1) produces IntervalWindows.
IntervalWindow day = (IntervalWindow) window;
String dataset = DatastoreConfigManager2.getString("dataflow.bigquery.dataset");
String tablePrefix = DatastoreConfigManager2.getString("dataflow.bigquery.tablenametemplate");
String dayString = DateTimeFormat.forPattern("yyyyMMdd")
.print(day.start());
String tableName = dataset + "." + tablePrefix + dayString;
LOG.info("Writing to BigQuery " + tableName);
return tableName;
}
})
where DatastoreConfigManager2 is
public class DatastoreConfigManager2 {
private static final DatastoreService DATASTORE = DatastoreServiceFactory.getDatastoreService();
private static final MemcacheService MEMCACHE = MemcacheServiceFactory.getMemcacheService();
static {
MEMCACHE.setErrorHandler(ErrorHandlers.getConsistentLogAndContinue(Level.INFO));
}
private static Set<String> configs = Sets.newConcurrentHashSet();
public static void registerConfig(String name) {
configs.add(name);
}
private static class DatastoreCallbacks {
// https://cloud.google.com/appengine/docs/java/datastore/callbacks
#PostPut
public void updateCacheOnPut(PutContext context) {
Entity entity = context.getCurrentElement();
if (configs.contains(entity.getKind())) {
String id = (String) entity.getProperty("id");
String value = (String) entity.getProperty("value");
MEMCACHE.put(id, value);
}
}
}
private static String lookup(String id) {
String value = (String) MEMCACHE.get(id);
if (value != null) return value;
else {
for (String config : configs) {
try {
PreparedQuery pq = DATASTORE.prepare(new Query(config)
.setFilter(new FilterPredicate("id", FilterOperator.EQUAL, id)));
for (Entity entity : pq.asIterable()) {
value = (String) entity.getProperty("value"); // use last
}
if (value != null) MEMCACHE.put(id, value);
} catch (Exception e) {
e.printStackTrace();
}
}
}
return value;
}
public static String getString(String id) {
return lookup(id);
}
}
When my pipeline runs on Dataflow I get the exception
Caused by: java.lang.NullPointerException
at com.google.appengine.api.NamespaceManager.get(NamespaceManager.java:101)
at com.google.appengine.api.memcache.BaseMemcacheServiceImpl.getEffectiveNamespace(BaseMemcacheServiceImpl.java:65)
at com.google.appengine.api.memcache.AsyncMemcacheServiceImpl.doGet(AsyncMemcacheServiceImpl.java:401)
at com.google.appengine.api.memcache.AsyncMemcacheServiceImpl.get(AsyncMemcacheServiceImpl.java:412)
at com.google.appengine.api.memcache.MemcacheServiceImpl.get(MemcacheServiceImpl.java:49)
at my.training.google.common.config.DatastoreConfigManager2.lookup(DatastoreConfigManager2.java:80)
at my.training.google.common.config.DatastoreConfigManager2.getString(DatastoreConfigManager2.java:117)
at my.training.google.mss.pipeline.InsertIntoBqWithCalendarWindow$1.apply(InsertIntoBqWithCalendarWindow.java:101)
at my.training.google.mss.pipeline.InsertIntoBqWithCalendarWindow$1.apply(InsertIntoBqWithCalendarWindow.java:95)
at com.google.cloud.dataflow.sdk.io.BigQueryIO$Write$Bound$TranslateTableSpecFunction.apply(BigQueryIO.java:1496)
at com.google.cloud.dataflow.sdk.io.BigQueryIO$Write$Bound$TranslateTableSpecFunction.apply(BigQueryIO.java:1486)
at com.google.cloud.dataflow.sdk.io.BigQueryIO$TagWithUniqueIdsAndTable.tableSpecFromWindow(BigQueryIO.java:2641)
at com.google.cloud.dataflow.sdk.io.BigQueryIO$TagWithUniqueIdsAndTable.processElement(BigQueryIO.java:2618)
Any suggestions? Thanks in advance.
EDIT: my functional requirement is building a pipeline with some configurable steps based on datastore entries.
How do I access the returned result from a service? The result is queried from the database and added to a ObservableList. I have a checkbox and wanted its value to depend on the result from the database.
How do I bind the checkbox so that its value(checked/unchecked) will depend on the rs.getString("studentForm137") field.
//cboxForm137.selectedProperty().bind(//I don't know the codes to bind checkbox);
Service
final Service<ObservableList<Student>> service = new Service<ObservableList<Student>>()
{
#Override
protected Task<ObservableList<Student>> createTask()
{
return new Task<ObservableList<Student>>()
{
#Override
protected ObservableList<Student> call() throws Exception
{
for (int i = 0; i < 250; i++)
{
updateProgress(i, 250);
Thread.sleep(2);
}
return student.display();
}
};
}
};
service.start();
Student Class
public class Student extends Person {
private SimpleStringProperty form137;
private SimpleStringProperty form138;
private SimpleStringProperty goodMoralCertificate;
private SimpleStringProperty birthCertificate;
private SimpleStringProperty highschoolDiploma;
public Student()
{
super();
}
public Student(String lastName, String firstName, String middleName,
String cpNumber, String address, String dateOfBirth,
String placeOfBirth, String emailAddress, String gender,
String fathersName, String mothersName,
String form137, String form138, String goodMoralCertificate,
String birthCertificate, String highschoolDiploma)
{
super(lastName, firstName, middleName,
cpNumber, address, dateOfBirth, placeOfBirth, emailAddress, gender,
fathersName, mothersName);
this.form137 = new SimpleStringProperty(form137);
this.form138 = new SimpleStringProperty(form138);
this.goodMoralCertificate = new SimpleStringProperty(goodMoralCertificate);
this.birthCertificate = new SimpleStringProperty(birthCertificate);
this.highschoolDiploma = new SimpleStringProperty(highschoolDiploma);
}
//form137
public String getForm137()
{
return form137.get();
}
public void setForm137(String form137)
{
this.form137.set(form137);
}
public StringProperty form137Property()
{
return form137;
}
//form138
public String getForm138()
{
return form138.get();
}
public void setForm138(String form138)
{
this.form138.set(form138);
}
public StringProperty form138Property()
{
return form138;
}
//goodMoralCertificate
public String getGoodMoralCertificate()
{
return goodMoralCertificate.get();
}
public void setGoodMoralCertificate(String goodMoralCertificate)
{
this.goodMoralCertificate.set(goodMoralCertificate);
}
public StringProperty goodMoralCertificateProperty()
{
return goodMoralCertificate;
}
//birthCertificate
public String getBirthCertificate()
{
return birthCertificate.get();
}
public void setBirthCertificate(String birthCertificate)
{
this.birthCertificate.set(birthCertificate);
}
public StringProperty birthCertificateProperty()
{
return birthCertificate;
}
//highschoolDiploma
public String getHighschoolDiploma()
{
return highschoolDiploma.get();
}
public void setHighschoolDiploma(String highschoolDiploma)
{
this.highschoolDiploma.set(highschoolDiploma);
}
public StringProperty highschoolDiplomaProperty()
{
return highschoolDiploma;
}
#Override
public ObservableList display()
{
Connection c = null;
PreparedStatement pst = null;
ResultSet rs = null;
ObservableList<Student> student = FXCollections.observableArrayList();
try
{
c = MySqlConnection.connect();
String SQL = "SELECT * " +
"FROM students ";
pst = c.prepareStatement(SQL);
rs = pst.executeQuery();
while(rs.next())
{
student.add(new Student(rs.getString("studentLastName"),
rs.getString("studentFirstName"),
rs.getString("studentMiddleName"),
rs.getString("studentCPNumber"),
rs.getString("studentAddress"),
rs.getString("studentDateOfBirth"),
rs.getString("studentPlaceOfBirth"),
rs.getString("studentEmailAddress"),
rs.getString("studentGender"),
rs.getString("studentFathersName"),
rs.getString("studentMothersName"),
rs.getString("studentForm137"),
rs.getString("studentForm138"),
rs.getString("studentGMC"),
rs.getString("studentNSO"),
rs.getString("studentHSDiploma")));
}
}
catch(Exception e)
{
System.out.println("Error on Building Data");
}
finally
{
try
{
PublicClass.closeConnection(c, pst, rs);
}
catch (SQLException ex)
{
Logger.getLogger(Student.class.getName()).log(Level.SEVERE, null, ex);
}
}
return student;
}
}
I have this Java class where I am writing the code for applying the overrides. I want to know if using ENUM is appropriate or if I need to use the switch case, how can I use it? Also, I have the for loop that I need to use as a common block of code for each override type. Apart from that, I do have few separate fields that I need to code for each override type.
public class EWFMService
{
private WorkbrainSystemAccessService wsa = new WorkbrainSystemAccessService();
private static final org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(EWFMService.class);
private final static String ovrCalcGrp = "ovrCalcGrp";
private DBConnection conn = null;
private int empId;
private Date ovrDate;
private String ovrTime;
private String ovrAction;
public List<EWFMServiceData> getProcessEWFMOverrides(String userName, String password, List<EWFMServiceInputData> inputData)
throws WSApplicationException{
logger.debug("EWFM Service");
wsa.logOn(userName, password);
List<EWFMServiceData> returnList = new ArrayList<EWFMServiceData> ();
logger.debug("userName = " + userName);
DBConnection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try{
conn = new DBConnection(ConnectionManager.getConnection());
for (int i = 0; i < inputData.size(); i++)
{
Here I want to retrieve the emp_id from the database, store the value in a variable and be able to use the variable in the rest of my program. How do I do it? To retrieve the emp_id, I am using the following query.
conn = new DBConnection(ConnectionManager.getConnection());
String sql = "SELECT EMP_ID FROM EMPLOYEE_HISTORY"
+ " WHERE EMP_VAL2 = **This is where I want to use the variable in which the values of emp_id will be stored. There can be more than 100 emp_ids**"
+ " AND SYSDATE BETWEEN EMPHIST_START_DATE AND EMPHIST_END_DATE";
EWFMServiceInputData inData = (EWFMServiceInputData) inputData.get(i);
OverrideType ot = OverrideType.getOverrideType(inData.getRecordType());
logger.debug("override type = " + ot.toString());
logger.debug("inputData ["+i+"] = " + inData.toString());
OverrideAccess oa = new OverrideAccess(conn);
OverrideData ovr = new OverrideData();
ovr.setOvrUdf4(inData.getReferenceId().toString());
if (ovrAction.equals("APPLY")) {
ovr.setOvrStatus(OverrideData.PENDING);
Here I want to determine the Action. If it is Apply, then I need to find out the recordType. So basically branch it out for each recordType using if else statements or enum as I believe switch doesn't support Java 1.5 which is what I am using. Then for each recordType, I branch out and write the appropriate code corresponding to that recordType. If Action is CANCEL, then I just write the following code.
} else if (ovrAction.equals("CANCEL")) {
String sql = "SELECT * FROM OVERRIDE"
+ " WHERE OVR_UDF4 = ?"
+ " AND OVRTYP_ID = ?";
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
while (rs.next()); {
ovr.assignByName(rs);
ovr.setUpdated(false);
ovr.setRetrieved(true);
ovr.setOvrStatus(OverrideData.CANCEL);
oa.save(ovr);
}
}
ovr.setEmpId(empId);
String strOvrDate = inData.getOvrStartDate();
ovr.setOvrStartDate(DateHelper.parseDate(strOvrDate, "MM/dd/yyyy"));
if (ovrStartTime != null) {
ovr.setOvrStartTime(ovrTime);
}
Object ovrEndDate;
if (ovrEndDate != null) {
ovr.setOvrEndDate(ovrDate);
}
Object ovrEndTime;
if (ovrEndTime!= null) {
ovr.setOvrEndTime(ovrTime);
}
ovr.setOvrComment(inData.getOvrComments());
ovr.setWbuName(inData.getWbuName());
ovr.setWbuNameActual(inData.getWbuNameActual());
ovr.setOvrNewValue("VAC");
ovr.setOvrCreateDate(new Date());
ovr.setOvrtypId(103);
oa.insert(ovr);
RuleEngine.runCalcGroup(conn,
empId,
ovrDate,
ovrDate);
//COMMON BLOCK ENDS HERE
EWFMServiceData outData = new EWFMServiceData();
outData.setReferenceId(inData.getReferenceId());
String [] status = {"SUCCESS", "ERROR", "LOCKED", "EXCEPTION"};
Random ran = new Random();
String gen = status[ran.nextInt(status.length)];
logger.debug("Status is" + status );
outData.setStatus(gen);
if (gen.equals("SUCCESS")){
outData.setErrorDetails("");
} else if (gen.equals("ERROR")) {
outData.setErrorDetails("Usage of time code VAC is not allowed; balance is insufficient." + " error");
} else if (gen.equals("LOCKED")) {
outData.setErrorDetails("Timesheet cannot be edited because it is locked for payroll close." + "locked");
} else if (gen.equals("EXCEPTION")) {
outData.setErrorDetails("{ML}QR_INCORRECT_CONDITION_PARAMETER{/ML}Error in condition AWA Is Self Override Condition: java.lang.NullPointerException{ARGS}AWA Is Self Override Conditionjava.lang.NullPointerException{/ARGS" + "exception");
}
returnList.add(outData);
}
}catch (Exception e){
logger.error("Error occured",e);
throw new WSApplicationException("Error retrieved",e);
}finally{
SQLUtil.cleanUp(conn, ps, rs);
}
wsa.logOff();
logger.debug("inputData+ ");
return returnList;
}
// I need to know if writing enum is okay or can I just write a switch case above in the for loop and branch each override type and declare their individual variables there? What's the best way? Can someone help me with the code?
public enum OverrideType {
WORKDETAIL,
WORKPREMIUM,
EMPLOYEESCHEDULE,
EMPLOYEE;
public static OverrideType getOverrideType(String recordType) {
if(recordType == null) {
throw new IllegalArgumentException("Record Type cannot be null");
}
if(recordType.equals("Work Detail")) {
return WORKDETAIL;
} else if (recordType.equals("Work Premium")) {
return WORKPREMIUM;
} else if (recordType.equals("Schedule")) {
return EMPLOYEESCHEDULE;
} else if (recordType.equals("Shift Pattern")) {
return EMPLOYEE;
} else {
throw new IllegalArgumentException("Record Type cannot be" + recordType);
}
}
}
}
THE OTHER FIELDS I NEED TO INCLUDE ARE AS FOLLOWS:
FOR WORKDETAIL, I NEED TO USE TIMECODE OF FORMAT THAT IS SENT BY THE CLIENT.
FOR WORK PREMIUM, I NEED TO USE TIMECODE OF FORMAT THAT IS SENT BY THE CLIENT AND ANOTHER FIELD IS MINUTES THAT GIVES THE NUMBER OF MINUTES WHICH IS ALSO SENT BY THE CLIENT.
Generally, using enums is appropriate, especially if you have a defined set of possible types.
You can also add behavior to the enums, which could make your enum a little bit more sophisticated:
public enum OverrideType {
WORKDETAIL("Work Detail"),
WORKPREMIUM("Work Premium"),
EMPLOYEESCHEDULE("Schedule"),
EMPLOYEE("Shift Pattern");
private String identifier;
private OverrideType(String identifier){
this.identifier = identifier;
}
public static OverrideType getOverrideType(String recordType) {
if(recordType == null) {
throw new IllegalArgumentException("Record Type cannot be null");
}
for (OverrideType ot : OverrideType.values()) {
if (recordType.equals(ot.identifier)) {
return ot;
}
}
return null;
}
}
The following example shows how to use an interface in enums or an abstract method definition:
public enum OverrideType implements OverrideTypeIF {
WORKDETAIL("Work Detail") {
public int getKey() {
return 0;
}
},
WORKPREMIUM("Work Premium") {
public int getKey() {
return 0;
}
},
EMPLOYEESCHEDULE("Schedule") {
public int getKey() {
return 0;
}
},
EMPLOYEE("Shift Pattern") {
public int getKey() {
return 0;
}
public void myInterfaceMethod() {
// do type specific behavior
}
};
private String identifier;
private OverrideType(String identifier){
this.identifier = identifier;
}
public abstract int getKey();
public void myInterfaceMethod() {
// do default behavior
}
public static OverrideType getOverrideType(String recordType) {
if(recordType == null) {
throw new IllegalArgumentException("Record Type cannot be null");
}
for (OverrideType ot : OverrideType.values()) {
if (recordType.equals(ot.identifier)) {
return ot;
}
}
return null;
}
}
public interface OverrideTypeIF {
void myInterfaceMethod();
}
I have a stored proc like this:
CREATE PROCEDURE [dbo].[Organisation_Insert]
#OrganisationXId uniqueidentifier
,#Enabled bit
,#Timezone nvarchar(50)
,#MinimumValue float
,#Rules ReminderRuleType READONLY ...
ReminderRuleType is a user defined type.
In my app I have this:
class OrganisationDTO
{
private readonly IOrganisationDocument _orgDoc;
public long OrganisationId { get { return _orgDoc.OrganisationId; } }
public Guid OrganisationXId { get { return _orgDoc.OrganisationXId; } }
public string TimeZone { get { return _orgDoc.TimeZone; } }
public bool Enabled { get { return _orgDoc.Enabled; } }
public decimal MinimumValue { get { return _orgDoc.MinimumValue; } }
public RuleTableValuedParameters Rules { get; private set; }
public OrganisationDTO(IOrganisationDocument orgDoc)
{
_orgDoc = orgDoc;
Rules = new RuleTableValuedParameters("#Rules", _orgDoc.Rules);
}
}
RuleTableValuedParameters implements SqlMapper.IDynamicParameters which has an AddParameters method.
When I execute the query, the #Rules parameter is never passed (using SQLProfiler). I can also see that AddParameters is never called.
Is this possible to do?
Thanks
Here's a simplified example based on your code that shows it working just fine; AddParameters is invoked correctly, and the values are conveyed to the stored procedure. As a side note: if you are using DataTable for your TVPs, the library supports that directly with no additional code needed.
public void SO29596645_TvpProperty()
{
try { connection.Execute("CREATE TYPE SO29596645_ReminderRuleType AS TABLE (id int NOT NULL)"); }
catch { }
connection.Execute(#"create proc #SO29596645_Proc (#Id int, #Rules SO29596645_ReminderRuleType READONLY)
as begin select #Id + ISNULL((select sum(id) from #Rules), 0); end");
var obj = new SO29596645_OrganisationDTO();
int val = connection.Query<int>("#SO29596645_Proc", obj.Rules, commandType: CommandType.StoredProcedure).Single();
// 4 + 9 + 7 = 20
val.IsEqualTo(20);
}
class SO29596645_RuleTableValuedParameters : Dapper.SqlMapper.IDynamicParameters {
private string parameterName;
public SO29596645_RuleTableValuedParameters(string parameterName)
{
this.parameterName = parameterName;
}
public void AddParameters(IDbCommand command, Dapper.SqlMapper.Identity identity)
{
Console.WriteLine("> AddParameters");
SqlCommand lazy = (SqlCommand)command;
lazy.Parameters.AddWithValue("Id", 7);
DataTable table = new DataTable {
Columns = {{"Id", typeof(int)}},
Rows = {{4}, {9}}
};
lazy.Parameters.AddWithValue("Rules", table);
Console.WriteLine("< AddParameters");
}
}
class SO29596645_OrganisationDTO
{
public SO29596645_RuleTableValuedParameters Rules { get; private set; }
public SO29596645_OrganisationDTO()
{
Rules = new SO29596645_RuleTableValuedParameters("#Rules");
}
}
Here's the full working DynamicParameter that I created:
public class OrganisationDynamicParameter : SqlMapper.IDynamicParameters
{
private readonly IOrganisation _orgModel;
public OrganisationDynamicParameter(IOrganisation orgModel)
{
_orgModel = orgModel;
}
public void AddParameters(IDbCommand command, SqlMapper.Identity identity)
{
SqlParameter p;
var sqlCommand = (SqlCommand)command;
sqlCommand.CommandType = CommandType.StoredProcedure;
p = sqlCommand.Parameters.Add("#OrganisationXId", SqlDbType.UniqueIdentifier);
p.Value = _orgModel.OrganisationXId;
p = sqlCommand.Parameters.Add("#Enabled", SqlDbType.Bit);
p.Value = _orgModel.Enabled;
p = sqlCommand.Parameters.Add("#Timezone", SqlDbType.NVarChar, 50);
p.Value = _orgModel.TimeZone;
p = sqlCommand.Parameters.Add("#MinimumValue", SqlDbType.Float);
p.Value = _orgModel.MinimumValue;
List<SqlDataRecord> ruleList = _orgModel.Rules.Select(MapRuleData).ToList();
if (ruleList.Count > 0)
{
p = sqlCommand.Parameters.Add("#Rules", SqlDbType.Structured);
p.Direction = ParameterDirection.Input;
p.TypeName = "ReminderRuleType";
p.Value = ruleList;
}
}
protected SqlDataRecord MapRuleData(IReminderRule value)
{
var rec = new SqlDataRecord(new[]
{
new SqlMetaData("RuleId", SqlDbType.BigInt),
new SqlMetaData("OrganisationId", SqlDbType.BigInt),
new SqlMetaData("Name", SqlDbType.NVarChar, 200),
new SqlMetaData("OffsetDays", SqlDbType.Int),
new SqlMetaData("SubjectTemplate", SqlDbType.NVarChar, -1),
new SqlMetaData("BodyTemplate", SqlDbType.NVarChar, -1)
});
rec.SetInt64(0, value.RuleId);
rec.SetInt64(1, value.OrganisationId);
rec.SetString(2, value.Name);
rec.SetInt32(3, value.OffsetDays);
rec.SetString(4, value.SubjectTemplate);
rec.SetString(5, value.BodyTemplate);
return rec;
}
}
I use this thusly:
public IOrganisation CreateOrganisation(IOrganisation organisation)
{
var dtoOrg = new OrganisationDynamicParameter(organisation);
return ExecuteSPReturningOrganisation("Organisation_Insert", dtoOrg);
}
protected IOrganisation ExecuteSPReturningOrganisation(string query, object parameters)
{
using (IDbConnection con = ConnectionFactory.CreateOpenConnection())
{
using (
SqlMapper.GridReader multi = con.QueryMultiple(query, parameters,
commandType: CommandType.StoredProcedure))
{
OrganisationModel org = multi.Read<OrganisationModel>().SingleOrDefault();
if (org != null)
{
org.Rules = multi.Read<ReminderRuleModel>().ToArray();
}
return org;
}
}
}
Cheers