Modifying the class level hashmap changes reflecting in local reference - java

I am trying to save insurance details to database based on insuranceid or updating if the insuranceid is already exists in the database. The problem is that when I am trying to save multiple insurance details it is giving ConcurrentModificationException. While debugging I found that 1st cycle it is ok that is 1st insurance details is successfully saving to database. But when next insurance details is storing it is giving the Exception. Another thing is that here I am modifying main HashMap(patientId,HashMap(insuranceId,InsuranceInfo)), and the changes are reflecting in local reference that is the id is adding to insuranceMap variable in the current method(). Please try to help me
this is my storing method...
public void storeInsuranceInformationToDataBase(int patientId) throws SQLException
{
//It gives arrayList of isuranceIds which are already in the data base.
ArrayList<Integer> insuranceIdsListInDatabase = getInsuranceIdsListInDatabase();
//It returns HashMap of insurance ids for given patient id.
HashMap<Integer, InsuranceInfo> insuranceMap = getInsuranceDetails(patientId);
Set<Integer> insuranceIdsInHashMap = insuranceMap.keySet();
//Here I am getting ConcurrentModificationException
for (int insuranceIdInHashMap : insuranceIdsInHashMap)
{
//Here I am comparing the both ids..
if (insuranceIdsListInDatabase.contains(insuranceIdInHashMap))
{
String updateInsuranceQuery = "UPDATE jp_InsuranceInfo SET typeOfPolicy='" + insuranceMap.get(insuranceIdInHashMap).getTypeOfPolicy() + "', amount=" + insuranceMap.get(insuranceIdInHashMap).getAmount() + ", duration=" + insuranceMap.get(insuranceIdInHashMap).getDuration()
+ ", companyName='" + insuranceMap.get(insuranceIdInHashMap).getCompanyName() + "' WHERE insuranceId=" + insuranceIdInHashMap + ";";
getDataBase().getStatement().executeUpdate(updateInsuranceQuery);
}
else
{
String insertInsuranceQuery = "INSERT INTO jp_InsuranceInfo VALUES(" + insuranceMap.get(insuranceIdInHashMap).getPatientId() + ",'" + insuranceMap.get(insuranceIdInHashMap).getTypeOfPolicy() + "'," + insuranceMap.get(insuranceIdInHashMap).getAmount() + ","
+ insuranceMap.get(insuranceIdInHashMap).getDuration() + ",'" + insuranceMap.get(insuranceIdInHashMap).getCompanyName() + "')";
getDataBase().getStatement().executeUpdate(insertInsuranceQuery);
ResultSet generatedInsuranceId = getDataBase().getStatement().executeQuery("SELECT SCOPE_IDENTITY()");
int newInsuranceId = 0;
if (generatedInsuranceId.next())
{
newInsuranceId = generatedInsuranceId.getInt(1);
}
//Here it returns an insurance object which contains insurance details
InsuranceInfo insuranceObject = insuranceMap.get(insuranceIdInHashMap);
insuranceObject.setInsuranceId(newInsuranceId);
//Here I am trying to store the newly inserted insurance object into main hashmap
storeInsuranceInfoToHashMap(patientId, insuranceObject);
//I am removing previous insurance object with temporary insurance id
getInsuranceMap().get(patientId).remove(insuranceIdInHashMap);
// Adding newly generated insurance id to array list
getInsuranceIdsListInDatabase().add(newInsuranceId);
}
}

Well, nothing strange. You trying to add a new item into the Map object while you're iterating through it.
My advise would be trying to save the insurance data you created when iterating through the Map into a temporary Map object. And, after you finished iterating the Map. Then, you could save the temporary map into the initial map.
example :
public void storeInsuranceInformationToDataBase(int patientId) throws SQLException
{
//It gives arrayList of isuranceIds which are already in the data base.
ArrayList<Integer> insuranceIdsListInDatabase = getInsuranceIdsListInDatabase();
//It returns HashMap of insurance ids for given patient id.
HashMap<Integer, InsuranceInfo> insuranceMap = getInsuranceDetails(patientId);
Map<Integer, InsuranceInfo> tempInsuranceMap = new HashMap<>();
Set<Integer> insuranceIdsInHashMap = insuranceMap.keySet();
//Here I am getting ConcurrentModificationException
for (int insuranceIdInHashMap : insuranceIdsInHashMap)
{
//Here I am comparing the both ids..
if (insuranceIdsListInDatabase.contains(insuranceIdInHashMap))
{
String updateInsuranceQuery = "UPDATE jp_InsuranceInfo SET typeOfPolicy='" + insuranceMap.get(insuranceIdInHashMap).getTypeOfPolicy() + "', amount=" + insuranceMap.get(insuranceIdInHashMap).getAmount() + ", duration=" + insuranceMap.get(insuranceIdInHashMap).getDuration()
+ ", companyName='" + insuranceMap.get(insuranceIdInHashMap).getCompanyName() + "' WHERE insuranceId=" + insuranceIdInHashMap + ";";
getDataBase().getStatement().executeUpdate(updateInsuranceQuery);
}
else
{
String insertInsuranceQuery = "INSERT INTO jp_InsuranceInfo VALUES(" + insuranceMap.get(insuranceIdInHashMap).getPatientId() + ",'" + insuranceMap.get(insuranceIdInHashMap).getTypeOfPolicy() + "'," + insuranceMap.get(insuranceIdInHashMap).getAmount() + ","
+ insuranceMap.get(insuranceIdInHashMap).getDuration() + ",'" + insuranceMap.get(insuranceIdInHashMap).getCompanyName() + "')";
getDataBase().getStatement().executeUpdate(insertInsuranceQuery);
ResultSet generatedInsuranceId = getDataBase().getStatement().executeQuery("SELECT SCOPE_IDENTITY()");
int newInsuranceId = 0;
if (generatedInsuranceId.next())
{
newInsuranceId = generatedInsuranceId.getInt(1);
}
//Here it returns an insurance object which contains insurance details
InsuranceInfo insuranceObject = insuranceMap.get(insuranceIdInHashMap);
insuranceObject.setInsuranceId(newInsuranceId);
//Here I am trying to store the newly inserted insurance object into main hashmap
storeInsuranceInfoToHashMap(patientId, insuranceObject); <-- make this function to save those information into the temporary map
//I am removing previous insurance object with temporary insurance id
getInsuranceMap().get(patientId).remove(insuranceIdInHashMap);
// Adding newly generated insurance id to array list
getInsuranceIdsListInDatabase().add(newInsuranceId);
}
}
insuranceMap.putAll(tempInsuranceMap);
}

Related

How to implement Room database query at runtime or dynamically

I need to create a room database query dynamically because I have lots of fields for UPDATE in the database.
If I used like below method then it works, but I have lots of fields that's why I can't create a separate UPDATE method like this.
#Query("UPDATE PROCEDUREMODEL SET patient_in_time = :val WHERE procedure_sr_number LIKE :sr")
void updateP(String val, String sr);
Now I try below but it does not work.
In DAO class I created this
#RawQuery
ProcedureModel updateProcedure(SupportSQLiteQuery supportSQLiteQuery);
And use like this
public static void updateProcedure(Context context, String colName, String val, String id) {
String s = "UPDATE PROCEDUREMODEL SET " + colName + " = :" + val + " WHERE procedure_sr_number LIKE :" + id;
SupportSQLiteQuery supportSQLiteQuery = new SimpleSQLiteQuery(s);
Thread thread = new Thread(() -> {
DatabaseHelper.getInstance(context).getDao().updateProcedure(supportSQLiteQuery);
});
thread.start();
}
I want to run the UPDATE query at runtime in Room database.
I believe that your issue is with the SQL being passed:-
String s = "UPDATE PROCEDUREMODEL SET " + colName + " = :" + val + " WHERE procedure_sr_number LIKE :" + id;
As the value val is non-numeric, because of the :'s (which you probably don't want), likewise for the id (if not numeric) the values should be enclosed in single quotes.
So using:-
String s = "UPDATE PROCEDUREMODEL SET " + colName + " = ':" + val + "' WHERE procedure_sr_number LIKE '" + id + "'";
would work. Although you very likely don't want the : as part of the value so you very likely want:-
String s = "UPDATE PROCEDUREMODEL SET " + colName + " = '" + val + "' WHERE procedure_sr_number LIKE '" + id + "'";
Saying that it is not recommended to apply literal values via string concatenation but to utilise parameter binding. This protects against SQL injection. As such you may wish to consider the following version:-
public static void updateProcedureBetter(Context context, String colName, String val, String id) {
String s = "UPDATE PROCEDUREMODEL SET " + colName + "=? WHERE procedure_sr_number LIKE ?";
Thread thread = new Thread(() -> {
DatabaseHelper.getInstance(context).getDao().updateProcedure(new SimpleSQLiteQuery(s,new Object[]{val,id}));
});
thread.start();
}
notice the ?'s in the SQL these being replaced by the objects in the Object[], the values being properly enclosed by SQLite parameter binding.
the replacement is on a 1 by/for 1 basis (first ? replace by first object in array, 2nd ? by second object ....)
note also that the intermediate supportSQLiteQuery object has been done away with.
component names (tables, columns etc) typically cannot be bound/changed so the column name has to be concatenated.

Error no such column in SQLite when updating rows

I'm trying to update data in rows in my DB, but i catch error that there's no such column (no such column 'Moscow' or another)
This is DBHelper code:
public static final String tableName = "currentWeather";
public static final String KEY_ID = "_id";
public static final String cityName = "city";
public static final String cityTemp = "temperature";
And creating DB:
sqLiteDatabase.execSQL("create table " + tableName + "(" + KEY_ID + "
integer primary key autoincrement,"
+ cityName + " text," + cityTemp + " text, " + " UNIQUE(" + cityName +
"))");
and error shows when i try to execSQl in response:
sqLiteDatabase.execSQL(
"UPDATE " + DBHelper.tableName + " SET " +
DBHelper.cityTemp + "=" +
response.body().getForecastMain().getTemp() + "
WHERE "
+ DBHelper.cityName + "=" + cityName);
I expect to update temperature data in rows by cityName
cityName and response.body().getForecastMain().getTemp() are strings and they should be passed surrounded with single quotes to the sql statement:
sqLiteDatabase.execSQL(
"UPDATE " + DBHelper.tableName + " SET " + DBHelper.cityTemp + "='" + response.body().getForecastMain().getTemp() + "'" +
"WHERE " + DBHelper.cityName + " = '" + cityName + "'"
);
But the recommended and safe way of doing the update is with the use of ContentValues and ? as placeholders for the parameters:
ContentValues cv = new ContentValues();
cv.put(DBHelper.cityTemp, String.valueOf(response.body().getForecastMain().getTemp()));
int rows = sqLiteDatabase.update(
DBHelper.tableName,
cv,
DBHelper.cityName + " = ?",
new String[] {cityName}
);
You can examine the value of the integer variable rows.
If it is 1 this means that 1 row was updated (because cityName is unique) so the update was successful.
I think you have changed column name or add new one (city). So you can fix it by two ways
By uninstall the application from phone
Add column name in upgrade method.
Example:
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// If you need to add a column
if (newVersion > oldVersion) {
db.execSQL("ALTER TABLE foo ADD COLUMN new_column INTEGER DEFAULT 0");
}
}
The thing is you need to wrap the values after the = sign in single quotations in the UPDATE statement. As for digits they work in both cases.
For example here is the correct syntax
UPDATE currentWeather
SET temperature = 45
WHERE
city = 'Moscow'
But in your code I'm assuming cityName has the value Moscow without the single quotation marks so the converted SQL code will be like this
UPDATE currentWeather
SET temperature = 45
WHERE
city = Moscow
Now the sql interpreter will think Moscow is some database object or column or something and not a literal value. So you need to surround your values in single quotation marks.
Also consider What the data type of response.body().getForecastMain().getTemp() is.
If it's int you have to parse it or something, as the data type of the related column is Text.

Inserting Content Values in multiple tables in Sqlite Android Application

I am brand new to multiple tables in an SQLite database and am trying to find out what the best practices are for inserting values into multiple tables. My main question is do I need to Create another ContentValues object for inserting the values into a second table? I am really stumped on how to perform the insert(). Here is what I am trying so far.
Here are the two tables and schema
/* Creating a common attributes table here. */
private static final String CREATE_COMMON_ATTRIBUTES_TABLE = "create table "
+ COMMON_ATTRIBUTES_TABLE + "(" + DBColCons.UID_COMMON_ATTRIBUTES + " integer" +
" primary key autoincrement, " + DBColCons.GPS_POINT+ " integer not null, "
+ DBColCons.EXISTING_GRADE_GPS_POINT+ " integer not null, "
+ DBColCons.COVER+ " real not null, "+ DBColCons.NOTES+ " text, "
+ DBColCons.DATE+ " text)";
/* Creating a weld table here */
private static final String CREATE_WELD_TABLE = " create table " +WELD_TABLE+ "("
+ DBColCons.UID_WELD + " integer primary key, " + DBColCons.WELD_TYPE +
" text, " + DBColCons.WELD_ID + " text, " + DBColCons.DOWNSTREAM_JOINT +
" text, " + DBColCons.UPSTREAM_JOINT + " text, " + DBColCons.HEAT_AHEAD +
" text, " + DBColCons.LENGTH_AHEAD + " real, " + DBColCons.WALL_CHANGE +
" text, " + DBColCons.WELD_WALL_THICKNESS + " text, "
+ DBColCons.WELDER_INITIALS + " text, foreign key("+DBColCons.WELD_ID+") references" +
"("+DBColCons.GPS_POINT+"))";
Here is the method I am wanting to use for the insert() with some class getters() for the Weld class, which I am passing in as a parameter.
public boolean insertWeld(Weld weld) {
/* Get a writable copy of the database */
SQLiteDatabase db = this.getWritableDatabase();
/* Content values to insert with Weld class setters */
ContentValues contentValuesWeld = new ContentValues();
try {
contentValuesWeld.put(DBColCons.GPS_POINT, weld.getGpsPoint());
contentValuesWeld.put(DBColCons.WELD_TYPE, weld.getWeldType());
contentValuesWeld.put(DBColCons.WELD_ID, weld.getWeldId());
contentValuesWeld.put(DBColCons.DOWNSTREAM_JOINT, weld.getDownstreamJoint());
contentValuesWeld.put(DBColCons.UPSTREAM_JOINT, weld.getUpstreamJoint());
contentValuesWeld.put(DBColCons.HEAT_AHEAD, weld.getHeatAhead());
contentValuesWeld.put(DBColCons.LENGTH_AHEAD, weld.getLengthAhead());
contentValuesWeld.put(DBColCons.EXISTING_GRADE_GPS_POINT, weld.getExistingGradePoint());
contentValuesWeld.put(DBColCons.COVER, weld.getCover());
contentValuesWeld.put(DBColCons.WALL_CHANGE, weld.getWallChange());
contentValuesWeld.put(DBColCons.WELD_WALL_THICKNESS, weld.getWeldWallThickness());
contentValuesWeld.put(DBColCons.WELDER_INITIALS, weld.getWelderInitials());
contentValuesWeld.put(DBColCons.NOTES, weld.getNotes());
/* adding the date in here to the row. */
contentValuesWeld.put(DBColCons.DATE, String.valueOf(mStrDate));
/* Inserting into the weld table */
db.insertWithOnConflict(WELD_TABLE, DBColCons.WELDER_INITIALS, contentValuesWeld,
SQLiteDatabase.CONFLICT_NONE);
return true;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
The values for DBColCons.GPS_POINT,DBColCons.EXISTING_GRADE_GPS_POINT,DBColCons.GPS_COVER and DBColCons.NOTES are what I want to insert into the Common_Attributes_Table. This is where I am really confused. Do I need to create a separate ContentValues object for those specific values and insert them into the desired table with a separate db.insert() method along with the one I am already using with the insert on the WELD_TABLE?
Help I am lost in this train wreck. Ha.
Thank you all.
You need to call insert() (or insertWithConflict()) for each table you are inserting values into. Unless the values are the same, this implies you will need another ContentValues per table.
If you intend for these inserts to be committed as a single atomic operation, consider using a transaction.
SQLiteDatabase db = ...;
db.beginTransaction();
try {
// do your inserts/etc. here
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}

My ResultSet will only print first row

I have a ResultSet that I know contains 8 rows of data because I checked it with a direct query of the DB. My code will only display the first row.
If anyone can give me some help I would greatly appreciate it. The first row is what should I expect it to be, I just don't know how to get it to move on to print subsequent rows.
term= Integer.parseInt(args[1]);
// Select a list of the surveys that fall under the term
query= "Select cid,subject,course_number,instructor_id from Courses where term=" + Integer.parseInt(args[1]);
result = statement.executeQuery(query);
String query2="";
while(result.next())
{
// Pull in the data
cid = result.getInt("cid");
subject = result.getString("subject");
courseNumber= result.getInt("course_number");
instructorId= result.getInt("instructor_id");enter code here
// Get the instructors last name
query2= "Select last_name from Instructors where fid=" + instructorId;
subResult= statement.executeQuery(query2);
while(subResult.next())
{
instructorLName= subResult.getString(1);
}
// Get the averages and num submitted
query2= "Select num_submitted, sum_q1, sum_q2, sum_q3, sum_q4, survey_id from surveys where cid=" + cid;
subResult= statement.executeQuery(query2);
while(subResult.next())
{
numSub= subResult.getInt(1);
sumQ1= subResult.getInt(2);
sumQ2= subResult.getInt(3);
sumQ3= subResult.getInt(4);
sumQ4= subResult.getInt(5);
surveyId= subResult.getInt(6);
}
// Print everything necessary
System.out.println( surveyId + " " + term + " " + subject + " " + courseNumber +
" " + instructorLName + " " + sumQ1/numSub + " " + sumQ2/numSub + " " + sumQ3/numSub
+ " " + sumQ4/numSub);
}
}
Not sure, but the problem might be that you are using same Statement object to execute different queries. Create separate statement instances for query and query2 and try.

MySQL INSERT with duplicate support

I'm trying to use a MySQL database to save player information, but whenever there is a duplicate it will load (or save?) every player from the same player column.
Here's what I'm working with:
public boolean saveGame(String playerName, String playerPass) {
String player = "'" + playerName + "', '" + playerPass + "'";
String player2 = "`password` = '" + playerPass + "'";
String playerData = "'" + playerName + "', 'testtttt'";
String playerData2 = "`test` = 'testtttt'";
Server.getConnectionPool().executeUpdate("INSERT INTO player (username, password) VALUES (" + player + ") ON duplicate KEY UPDATE " + player2);
Server.getConnectionPool().executeUpdate("INSERT INTO playerdata (username, test) VALUES (" + playerData + ") ON duplicate KEY UPDATE " + playerData2);
return true;
}
public int loadGame(String name, String pass) {
ResultSet res = Server.getConnectionPool().executeQuery("SELECT * FROM player, playerdata WHERE player.username = '" + name + "'");
try {
name = res.getString("username");
if (!pass.equalsIgnoreCase(res.getString("password"))) {
return 3;
}
} catch (Exception e) {
e.printStackTrace();
}
return 1;
}
Here are the schemas (I removed the data from the example as it's not really needed, it doesn't load/save properly regardless):
Player:
image http://puu.sh/Alit.png
Playerdata:
image http://puu.sh/Aljr.png
I'm aware they'll be the same because I'm using the same string for the test field, but even if I do random ones or custom edit it in PHPMyAdmin it'll still save and then load from the same column. I think that it's saving because it seems to load the player properly, it's just not updating the proper column, which I don't know how to do. Inside the playerdata table all of the data for every single person is the same, and I don't know what's causing it, any ideas?
I have fixed this issue by changing the loading query to SELECT * FROM player as p, playerdata as pd WHERE p.username = '" + name + "' AND pd.username = '" + name + "'
If you want to insert duplicate record in your database, please remove primary key(username) from both tables.so you don't want to insert duplicate records, please use JDBC transactions.The following is sample usage;
Server.getConnectionPool().setAutoCommit(false);
Server.getConnectionPool().executeUpdate("INSERT INTO player (username, password) VALUES (" + player + ") ON duplicate KEY UPDATE " + player2);
Server.getConnectionPool().executeUpdate("INSERT INTO playerdata (username, test) VALUES (" + playerData + ") ON duplicate KEY UPDATE " + playerData2);
Server.getConnectionPool().commit();
Details usage can learn here.

Categories

Resources