I have created an app where I try to insert a record with the latest order number increased by one.
The main function is triggered from Activity, however, the whole process is in my ViewModel.
Issue no 1, After I insert a new record the order by number is not updated.
Issue no 2, When I insert first record the order by number is null, for that reason I am checking for null and setting the value to 0.
My goal here is to get the latest order_by number from Entity in my ViewModel, increased by 1 and add that new number to my new record using fun addTestData(..).
Entity:
#Entity(tableName = "word_table")
data class Word(
#ColumnInfo(name = "id") val id: Int,
#ColumnInfo(name = "word") val word: String,
#ColumnInfo(name = "order_by") val orderBy: Int
Dao:
#Query("SELECT order_by FROM word_table ORDER BY order_by DESC LIMIT 1")
suspend fun getHighestOrderId(): Int
Repository:
#Suppress("RedundantSuspendModifier")
#WorkerThread
suspend fun getHighestOrderId(): Int {
return wordDao.getHighestOrderId()
}
ViewModel:
private var _highestOrderId = MutableLiveData<Int>()
val highestOrderId: LiveData<Int> = _highestOrderId
fun getHighestOrderId() = viewModelScope.launch {
val highestOrderId = repository.getHighestOrderId()
_highestOrderId.postValue(highestOrderId)
}
fun addTestData(text: String) {
for (i in 0..1500) {
getHighestOrderId()
var highestNo = 0
val highestOrderId = highestOrderId.value
if (highestOrderId == null) {
highestNo = 0
} else {
highestNo = highestOrderId
}
val addNumber = highestNo + 1
val word2 = Word(0, text + "_" + addNumber,addNumber)
insertWord(word2)
}
}
Activity:
wordViewModel.addTestData(text)
In my Spring application with Kotlin, I am reading a sql table that has many nullable columns. For a nullable column I using this if-expression:
if (rs.getObject("ordernumber") != null) rs.getInt("ordernumber") else null
Is there an easier way than writing an if-expression for each nullable column?
I have simplified the example to one nullable column, but of course I have many more nullable columns with String, Integer, Timestamp and so on.
fun getEmployeePayRecord(employee: Employee): List<EmployeePayRecord> {
val rowMapper: RowMapper<EmployeePayRecord> = RowMapper { rs, _ ->
EmployeePayRecord(
uuid = rs.getString("uuid"),
workingDay = rs.getTimestamp("working_day").toLocalDateTime(),
orderNumber = if (rs.getObject("ordernumber") != null) rs.getInt("ordernumber") else null
)
}
return jdbcTemplate.query(
"""select uuid
, working_day
, ordernumber
from plrv11.employee_pay_record
where employee_number = :employeeNumber
order by working_day
""", rowMapper, employee.employeeNumber
).toList()
}
EDIT
I have taken up M. Deinum's and David's ideas and added extension functions, like this:
fun ResultSet.getIntOrNull(columnName: String): Int? {
val result = getInt(columnName)
return if (wasNull()) null else result
}
Now given a hive table with its schema, namely:
hive> show create table nba_player;
OK
CREATE TABLE `nba_player`(
`id` bigint,
`player_id` bigint,
`player_name` string,
`admission_time` timestamp,
`nationality` string)
ROW FORMAT SERDE
'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe'
STORED AS INPUTFORMAT
'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat'
LOCATION
'hdfs://endpoint:8020/user/hive/warehouse/nba_player'
TBLPROPERTIES (
'transient_lastDdlTime'='1541140811')
Time taken: 0.022 seconds, Fetched: 16 row(s)
How to infer its parquet schema without inserting any records?
The parquet schema is like:
message_meta
{optional int64 id;
optional int64 player_id;
optional binary player_name;
optional timestamp admission_time;
optional binary nationality;}
The code is shown as below
/**
* Generate MessageType by table properties using HiveSchemaConverter
*
* #param tableProperties {#link Properties}
* #return MessageType
*/
public static MessageType getMessageTypeFromTable(final Properties tableProperties) {
final String columnNameProperty = tableProperties.getProperty(IOConstants.COLUMNS);
final String columnTypeProperty = tableProperties.getProperty(IOConstants.COLUMNS_TYPES);
List<String> columnNames;
List<TypeInfo> columnTypes;
if (columnNameProperty.length() == 0) {
columnNames = new ArrayList<String>();
} else {
columnNames = Arrays.asList(columnNameProperty.split(","));
}
if (columnTypeProperty.length() == 0) {
columnTypes = new ArrayList<TypeInfo>();
} else {
columnTypes = TypeInfoUtils.getTypeInfosFromTypeString(columnTypeProperty);
}
MessageType messageType = HiveSchemaConverter.convert(columnNames, columnTypes);
logger.info("messageType is inferred to be: {}", messageType.toString());
return messageType;
}
public class ParquetHelperTest {
#Test
public void testGenerateParquetSchemaFromTableProperties() {
Properties tableProperties = new Properties();
tableProperties.setProperty(IOConstants.COLUMNS, "id,player_id,player_name,admission_time,nationality");
tableProperties.setProperty(IOConstants.COLUMNS_TYPES, "bigint,bigint,string,timestamp,string");
MessageType messageType = ParquetHelper.getMessageTypeFromTable(tableProperties);
String expectedMessageType = "message hive_schema {\n"
+ " optional int64 id;\n"
+ " optional int64 player_id;\n"
+ " optional binary player_name (UTF8);\n"
+ " optional int96 admission_time;\n"
+ " optional binary nationality (UTF8);\n"
+ "}";
String calculatedMessageType = messageType.toString();
calculatedMessageType = calculatedMessageType.replaceAll("\\s", "");
expectedMessageType = expectedMessageType.replaceAll("\\s", "");
Assert.assertTrue(calculatedMessageType.equalsIgnoreCase(expectedMessageType));
}
}
I am trying to update certain rows in my oracle DB using id which is of RAW(255).
Sample ids 0BF3957A016E4EBCB68809E6C2EA8B80, 1199B9F29F0A46F486C052669854C2F8...
#Autowired
private NamedParameterJdbcTemplate jdbcTempalte;
private static final String UPDATE_SUB_STATUS = "update SUBSCRIPTIONS set status = :status, modified_date = systimestamp where id in (:ids)";
public void saveSubscriptionsStatus(List<String> ids, String status) {
MapSqlParameterSource paramSource = new MapSqlParameterSource();
List<String> idsHexToRaw = new ArrayList<>();
String temp = new String();
for (String id : ids) {
temp = "hextoraw('" + id + "')";
idsHexToRaw.add(temp);
}
paramSource.addValue("ids", idsHexToRaw);
paramSource.addValue("status", status);
jdbcTempalte.update(*UPDATE_SUB_STATUS*, paramSource);
}
This above block of code is executing without any error but the updates are not reflected to the db, while if I skip using hextoraw() and just pass the list of ids it works fine and also updates the data in table. see below code
public void saveSubscriptionsStatus(List<String> ids, String status) {
MapSqlParameterSource paramSource = new MapSqlParameterSource();]
paramSource.addValue("ids", ids);
paramSource.addValue("status", status);
jdbcTempalte.update(UPDATE_SUB_STATUS, paramSource);
}
this code works fine and updates the table, but since i am not using hextoraw() it scans the full table for updation which I don't want since i have created indexes. So using hextoraw() will use index for scanning the table but it is not updating the values which is kind of weird.
Got a solution myself by trying all the different combinations :
#Autowired
private NamedParameterJdbcTemplate jdbcTempalte;
public void saveSubscriptionsStatus(List<String> ids, String status) {
String UPDATE_SUB_STATUS = "update SUBSCRIPTIONS set status = :status, modified_date = systimestamp where id in (";
MapSqlParameterSource paramSource = new MapSqlParameterSource();
String subQuery = "";
for (int i = 0; i < ids.size(); i++) {
String temp = "id" + i;
paramSource.addValue(temp, ids.get(i));
subQuery = subQuery + "hextoraw(:" + temp + "), ";
}
subQuery = subQuery.substring(0, subQuery.length() - 2);
UPDATE_SUB_STATUS = UPDATE_SUB_STATUS + subQuery + ")";
paramSource.addValue("status", status);
jdbcTempalte.update(UPDATE_SUB_STATUS, paramSource);
}
What this do is create a query with all the ids to hextoraw as id0, id1, id2...... and also added this values in the MapSqlParameterSource instance and then this worked fine and it also used the index for updating my table.
After running my new function the query look like : update
SUBSCRIPTIONS set status = :status, modified_date = systimestamp
where id in (hextoraw(:id0), hextoraw(:id1), hextoraw(:id2)...)
MapSqlParameterSource instance looks like : {("id0", "randomUUID"),
("id1", "randomUUID"), ("id2", "randomUUID").....}
Instead of doing string manipulation, Convert the list to List of ByteArray
List<byte[]> productGuidByteList = stringList.stream().map(item -> GuidHelper.asBytes(item)).collect(Collectors.toList());
parameters.addValue("productGuidSearch", productGuidByteList);
public static byte[] asBytes(UUID uuid) {
ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
bb.putLong(uuid.getMostSignificantBits());
bb.putLong(uuid.getLeastSignificantBits());
return bb.array();
}
I'm using subselect in hibernate to return an object that contains id on all related table instead of object.
this the dto that I defined
#Entity
#Subselect("select di.id as id, user.id as userId, client.id as clientId, controller.id as controllerId,"
+ "supplier.id as supplierId, grade.id as gradeId, packing.id as packingId, warehouse.id as warehouseId,"
+ "qualityController.id as qualityControllerId,"
+ "companyMasterByPledger.id as pledgerId,"
+ "di.refNumber as refNumber,"
+ "di.clientRef as clientRef,"
+ "di.date as date,"
+ "di.supplierRef as supplierRef,"
+ "di.tons as tons,"
+ "di.kgPerBag as kgPerBag,"
+ "di.noOfBags as noOfBags,"
+ "di.deliveryDate as deliveryDate,"
+ "di.fromTime as fromTime,"
+ "di.toTime as toTime,"
+ "di.markingOnBags as markingOnBags,"
+ "di.originId as originId,"
+ "di.qualityId as qualityId,"
+ "di.remarks as remarks,"
+ "di.status as status,"
+ "di.log as log "
+ "from DeliveryInstruction as di "
+ "left join di.user as user "
+ "left join di.companyMasterByClientId as client "
+ "left join di.companyMasterByWeightControllerId as controller "
+ "left join di.companyMasterBySupplierId as supplier "
+ "left join di.gradeMaster as grade "
+ "left join di.packingMaster as packing "
+ "left join di.companyMasterByQualityControllerId as qualityController "
+ "left join di.companyMasterByPledger as pledger "
+ "left join di.warehouse as warehouse")
#Synchronize({"DeliveryInstruction"})
public class DeliveryView implements Serializable{
private Integer id;
private Integer userId;
private Integer clientId;
private Integer controllerId;
private Integer supplierId;
private Integer gradeId;
private Integer packingId;
private Integer warehouseId;
private Integer qualityControllerId;
private Integer pledgerId;
private String refNumber;
private String clientRef;
private Date date;
private String supplierRef;
private Double tons;
private Float kgPerBag;
private Integer noOfBags;
private Date deliveryDate;
private String fromTime;
private String toTime;
private String markingOnBags;
private Integer originId;
private Integer qualityId;
private String remark;
private Byte status;
private String log;
public DeliveryView() {
}
public DeliveryView(Integer id, Integer userId, Integer clientId, Integer controllerId, Integer supplierId, Integer gradeId, Integer packingId, Integer warehouseId, Integer qualityControllerId, Integer pledgerId, String refNumber, String clientRef, Date date, String supplierRef, Double tons, Float kgPerBag, Integer noOfBags, Date deliveryDate, String fromTime, String toTime, String markingOnBags, Integer originId, Integer qualityId, String remark, Byte status, String log) {
this.id = id;
this.userId = userId;
this.clientId = clientId;
this.controllerId = controllerId;
this.supplierId = supplierId;
this.gradeId = gradeId;
this.packingId = packingId;
this.warehouseId = warehouseId;
this.qualityControllerId = qualityControllerId;
this.pledgerId = pledgerId;
this.refNumber = refNumber;
this.clientRef = clientRef;
this.date = date;
this.supplierRef = supplierRef;
this.tons = tons;
this.kgPerBag = kgPerBag;
this.noOfBags = noOfBags;
this.deliveryDate = deliveryDate;
this.fromTime = fromTime;
this.toTime = toTime;
this.markingOnBags = markingOnBags;
this.originId = originId;
this.qualityId = qualityId;
this.remark = remark;
this.status = status;
this.log = log;
}
#Id
public Integer getId() {
return id;
}
// ... others getter and setter
}
and in the DAO class, the method looks like below
public DeliveryView getDiById(int id) {
return (DeliveryView) getHibernateTemplate().get(DeliveryView.class, id);
}
However when I use the above method, it returned null.
When I run the method, the script that is printed to the console is
select deliveryvi0_.id as id36_0_, deliveryvi0_.clientId as clientId36_0_, deliveryvi0_.clientRef as clientRef36_0_, deliveryvi0_.controllerId as controll4_36_0_, deliveryvi0_.date as date36_0_, deliveryvi0_.deliveryDate as delivery6_36_0_, deliveryvi0_.fromTime as fromTime36_0_, deliveryvi0_.gradeId as gradeId36_0_, deliveryvi0_.kgPerBag as kgPerBag36_0_, deliveryvi0_.log as log36_0_, deliveryvi0_.markingOnBags as marking11_36_0_, deliveryvi0_.noOfBags as noOfBags36_0_, deliveryvi0_.originId as originId36_0_, deliveryvi0_.packingId as packingId36_0_, deliveryvi0_.pledgerId as pledgerId36_0_, deliveryvi0_.qualityControllerId as quality16_36_0_, deliveryvi0_.qualityId as qualityId36_0_, deliveryvi0_.refNumber as refNumber36_0_, deliveryvi0_.remark as remark36_0_, deliveryvi0_.status as status36_0_, deliveryvi0_.supplierId as supplierId36_0_, deliveryvi0_.supplierRef as supplie22_36_0_, deliveryvi0_.toTime as toTime36_0_, deliveryvi0_.tons as tons36_0_, deliveryvi0_.userId as userId36_0_, deliveryvi0_.warehouseId as warehou26_36_0_ from DeliveryView deliveryvi0_ where deliveryvi0_.id=?
it gets the data from DeliveryView table which does not exist, what I want is to get the data from DeliveryInstruction table. Please help me to correct it, thanks
P/s: I'm using spring and hibernate and I do this way to work with jackson to prevent it load a lot of redundant information (I used jackson hibernate module, but it returned a lot of unneccessary information, instead of only id). So if you have any better idea, please tell me, thanks.
Update: I saw that the script on #subselect didn't run, it execute the default script "select * from deliveryView" when I call "get(DeliveryView.class, id)" method.
Update: This my native script that I've checked
select di.id as id, user.id as userId, client.id as clientId, controller.id as controllerId,
supplier.id as supplierId, grade.id as gradeId, packing.id as packingId, warehouse.id as warehouseId,
qualityController.id as qualityControllerId,
pledger.id as pledgerId,
di.ref_number as refNumber,
di.client_ref as clientRef,
di.date as date,
di.supplier_ref as supplierRef,
di.tons as tons,
di.kg_per_bag as kgPerBag,
di.no_of_bags as noOfBags,
di.delivery_date as deliveryDate,
di.from_time as fromTime,
di.to_time as toTime,
di.marking_on_bags as markingOnBags,
di.origin_id as originId,
di.quality_id as qualityId,
di.remark as remarks,
di.status as status,
di.log as log
from delivery_instruction di
left join user on user.id = di.user_id
left join company_master client on client.id = di.client_id
left join company_master controller on controller.id = di.weight_controller_id
left join company_master supplier on supplier.id = di.supplier_id
left join grade_master grade on grade.id = di.grade_id
left join packing_master packing on packing.id = di.packing_id
left join company_master qualityController on qualityController.id = di.quality_controller_id
left join company_master pledger on pledger.id = di.pledger
left join warehouse on warehouse.id = di.warehouse_id
where di.id = 21
1 Create simple class(without annotations) that holds all properties you need with getters and setters
2 Execute native sql:
public DeliveryView getDiById(int id) {
DeliveryView dV = (DeliveryView) sessionFactory.getCurrentSession()
.createSQLQuery(yourQueryHere).setResultTransformer(
new AliasToBeanResultTransformer(DeliveryView.class)).uniqueResult();
return dV;
}