Letting Android choose the next SQLITE _ID - java

Somewhere in my code I do this:
contentValues = new ContentValues();
// contentValues.put("_ID",BaseColumns._ID); // Not Working can someone explain what this is and how it's used BaseColumns._ID ?
contentValues.put("_ID", null); // Not working, Everywhere they say to pass in a null value and Android will do it's magic ...
contentValues.put("_ID", "1") // This works but has to be changed manually every time
contentValues.put("login", username.getText().toString());
contentValues.put("password", pwd.getText().toString());
contentValues.put("type", type);
This is my small schema:
public static final String CREATE_DATABASE = "CREATE TABLE "+
TABLE +"(_ID INTEGER PRIMARY KEY AUTOINCREMENT, login VARCHAR(50) NOT NULL, password VARCHAR(50) NOT NULL, type CHAR(1) NOT NULL)";
Some people say not to put AUTOINCREMENT, but in some other websites you can see it in the code. I'm not sure what to do anymore.
How do I get Android to choose the next increment value ?

Using autoincrement will auto assign an ID to any new row inserted into the database
You do not need to call contentValues.put("_ID", null); or even access the column in any way when you insert something into the database, it is done automatically

Related

Prepared Statement Primary Key store seed 1 and increment

Okay, so I just started JDBC with derby client and I'm kind of new with it.
I set column ID as primary key with int as it's data type. However, I'm not sure if I should include myStatement.setString(1, ?); because I thought it should Auto Increment but it looks like it's not doing it.
Here's my Grab file details:
create table "ADMIN1".STUDENTPERSONALDETAILS
(
ID INTEGER not null primary key,
STUDENTID VARCHAR(10) not null,
LASTNAME VARCHAR(50) not null,
FIRSTNAME VARCHAR(50) not null,
MIDDLENAME VARCHAR(50) not null,
PLACEOFBIRTH VARCHAR(200) not null,
DOB VARCHAR(50) not null,
GENDER VARCHAR(4) not null,
CIVILSTATUS VARCHAR(7) not null,
RELIGION VARCHAR(15) not null,
NATIONALITY VARCHAR(20) not null
)
How can I correct my PreparedStatement or My Table in such a way that adding of value for column ID will be automatic so that I can start setString(2, studentID) and avoid getting error about the number of columns not matching with what was supplied?
Here's my code:
addButton.addActionListener(new ActionListener () {
#Override
public void actionPerformed(ActionEvent e) {
try {
String myDbUrl = "jdbc:derby://localhost:1527/Enrollment"; //stores url to string
String userName = "admin1";
String Password = "admin1";
Connection myDBConnection = DriverManager.getConnection(myDbUrl, userName, Password);
String myQuery = "INSERT INTO STUDENTPERSONALDETAILS"
+ "(STUDENTID,LASTNAME,FIRSTNAME,MIDDLENAME,PLACEOFBIRTH,DOB,GENDER,CIVILSTATUS,RELIGION,NATIONALITY) "
+ "VALUES(?,?,?,?,?,?,?,?,?,?) ";
String adminissionNo ;
String studentID = tfStudentId.getText().toString();
String lastName = tfLastName.getText().toString();
String firstName = tfFirstName.getText().toString();
String middleName = tfMiddleName.getText().toString();
String placeOfBirth = tfPob.getText().toString();
String dateOfBirth = listDOB.getSelectedItem().toString();
String gender = listGender.getSelectedItem().toString();
String civilStatus = listCivilStatus.getSelectedItem().toString();
String religion = listReligion.getSelectedItem().toString();
String nationality = listNationality.getSelectedItem().toString();
PreparedStatement myStatement = myDBConnection.prepareStatement(myQuery);
myStatement.setString(2, lastName);
myStatement.setString(3, firstName);
myStatement.setString(4, middleName);
myStatement.setString(5, placeOfBirth);
myStatement.setString(6, dateOfBirth);
myStatement.setString(7, gender);
myStatement.setString(8, civilStatus);
myStatement.setString(9, religion);
myStatement.setString(10, nationality);
boolean insertResult = myStatement.execute();
if(insertResult == true)
JOptionPane.showMessageDialog(null, "Successfully Added Information");
else
JOptionPane.showMessageDialog(null, "Encountered an error while inserting data");
}
catch(SQLException ex) {
JOptionPane.showMessageDialog(null, ex.toString());
}
}
});
Is it necessary to include myStatement.setString(1, integervaluehere) for Primary Keys? Isn't it supposed to autoincrement?
I'd appreciate any explanation because I just started learning the basics of PreparedStatements recently.
I tried counting the columns and tried 10 and 11 lines of myStatement.setString(), but still can't get it to insert data because of mismatch.
Thanks in advance.
You need to mention 'auto increment' explicitly.
Or you can write your own java code to track the Id for each table and whenever you ask the method to give the ID it will return lastID + 1.
But, I think now you can go with auto_increment option.
If you want it to autoincrement you need to say so in the column definition, and you haven't.
I don't know what 'default 1' in your title is supposed to mean, as you haven't mentioned it in your question, but you can't have a default value and autoincrement. It doesn't make sense.
I don't know what 'store seed 1' means either, in your edit.
When you have a column with a default value you want to rely on, or autoincrement, you don't mention it at all in the INSERT statement, so there is no positional argument to set.
First, set the primary identifier column to autoincrement. Since your query already excludes the primary key, you then only have to change the PreparedStatement indexes to match the number of parameters in your query starting from one.
Since you have 10 columns in addition to the primary ID column, your PreparedStatement might look something like the following:
PreparedStatement myStatement = myDBConnection.prepareStatement(myQuery);
myStatement.setString(1, studentId);
myStatement.setString(2, lastName);
myStatement.setString(3, firstName);
myStatement.setString(4, middleName);
myStatement.setString(5, placeOfBirth);
myStatement.setString(6, dateOfBirth);
myStatement.setString(7, gender);
myStatement.setString(8, civilStatus);
myStatement.setString(9, religion);
myStatement.setString(10, nationality);
Note that you do not need to have the instruction, myStatement.setInt(1, primaryId);, once you have changed the primary key in your table to auto-increment. However, if you elect to keep the primary key as non-autoincrementing, then you must explicitly specify the primary key value and provide a parameter in your query to insert that data.
If you're using MySQL Workbench, which if you're not, I highly recommend because it just works. You have to choose Auto-Increment as a characteristic of that column. If you want your column to auto increment, when creating columns in your database, check the option Auto-Increment, sometimes written as AI.

Ways to dynamically change SQL database through JafaFx table Cell editing

My javaFx application has many tables with editable table cells to populate data from sql database.I also want to make changes in database after data editing through table cells.According to this toturial "https://docs.oracle.com/javafx/2/ui_controls/table-view.htm"
I have created my editable table cell with the following code.
item_price_col.setCellValueFactory(
new PropertyValueFactory("price")
);
item_price_col.setCellFactory(TextFieldTableCell.forTableColumn());
item_price_col.setOnEditCommit(
new EventHandler<CellEditEvent<Item, String>>() {
#Override
public void handle(CellEditEvent<Item,String> t) {
String old_price=t.getOldValue();
((Item) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setPrice(t.getNewValue());
String new_price=t.getNewValue();
System.out.println("Old Price:"+old_price);
System.out.println("New Price:"+new_price);
}
}
);
But it doesn't make any changes in database after editing.So,I think have to write update Query inside of that handle method.But I can only know old value and new value. I can't make query statement like that "update item set price=new_price where price=old_price".If I update a single price of a item to new value,every items in my item table that have the same price with my edited item will make changes to new price value.Are there any ways to solve this problem?
Here is my item table structure.
item | CREATE TABLE `item` (
`code` int(11) NOT NULL,
`name` varchar(50) DEFAULT NULL,
`price` varchar(50) NOT NULL,
`whole_sale_price` varchar(50) NOT NULL,
`orginal_price` varchar(50) DEFAULT NULL,
PRIMARY KEY (`code`),
UNIQUE KEY `code` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
Keep an id field to your item as it is given in the database.
If you have not primary or unique key in the database probably you made some architectural mistake. Anyway there is a row id specified in some database servers.
private int id; // id field for item object.
While updating include id as condition.
update sometable set price = item.getPrice() where id = item.getId();
I know sql is not well written but I hope you'll get it
And you don't have to show value of id field in your table grid.
This technique is used in most systems
EDITED 2015.12.18
You have code column in the table. Retrieve by jdbc into your item object's id field.
There is an example
http://www.tutorialspoint.com/jdbc/jdbc-update-records.htm

How to Insert a value where not exist in SQLite Android

I want to insert values into my table only when values don't exist in the table.
String CREATETABLE = "CREATE TABLE contacts ( " +
"id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"name TEXT, "+
"phone TEXT )";
Here is my code to create the table, I used UNIQUE(phone), and it doesn't work.
And to add a new contact I am using this code:
ContentValues values = new ContentValues();
values.put("name", contact.getName()); // get title
values.put("phone", contact.getNumero()); // get author
// 3. insert
db.insert("contacts", // table
null, //nullColumnHack
values);
I don't think there is a way of doing that without retrieving the row first. You query the database looking for that particular contact (which you have to specify at least one column to be unique, or any combination of columns to be primary key) otherwise how would you handle two person with the same name?.
So you query and search for the desired person, if you find it, check if the column is null and a) insert if it is, b) ignore if it isn't. If the query doesn't find any person, you cant just insert.
About the unique constraint, its like this:
String CREATETABLE = "CREATE TABLE contacts ( " +
"id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"name TEXT, " +
"phone TEXT UNIQUE)";
In your sample you are using SQLiteDatabase.insert(), try to use SQLiteDatabase.insertWithOnConflict() with one of values CONFLICT_IGNORE, CONFLICT_REPLACE or others.
Also have a look about implementing database as ContentProvider which is much harder to understand but really good to know.

Update table with primary key and unique columns using Hibernate and mySQL

I have a table containing four columns:
CREATE TABLE `participants` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(128) NOT NULL,
`function` VARCHAR(255) NOT NULL,
`contact` VARCHAR(255) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `name_function_contact` (`name`, `function`, `contact`)
)
From the application I get participants-objects, which might have values for name, functionand contactwhich are already in that exact matter in the database. In this case I want Hibernate to get me the idof that object, otherwise I want to save the object.
Using saveOrUpdate()I just get an:
org.hibernate.exception.ConstraintViolationException: Duplicate entry 'NAME-FUNCTION-CONTACT: NAME' for key 'name_function_contact'
How can I accomplish this? Thanks a lot!
Since the answers suggested that Hibernate cannot do it on its own (bummer!) I solved it the "native sql" way:
Participants tempParti = ((Participants) session.createQuery("FROM Participants WHERE name = '" + p.getName() + "' AND function = '" + p.getFunction() + "' AND contact = '" + p.getContact() + "'").uniqueResult());
if (tempParti != null) {
p = tempParti;
} else {
session.save(p);
}
Works like a charm! Thanks to all of you!
I am no expert in Hibernate. But from Mysql perspective, you do the following.
use INSERT IGNORE INTO... to add the value in the table. If the number of rows inserted is 0, then you can manually get the ID of the row by a SELECT statement.
EDIT: LAST_INSERT_ID() was wrong here. I have edited the answer.

Java Swing & Postgres user authentication: Close old connection when new connection opened

I have a Java Swing application that accesses a Postgres database using a simple Singleton Pattern:
public class DatabaseConnection {
private static final String uname = "*******";
private static final String pword = "*******";
private static final String url = "*******************************";
Connection connection;
// load jdbc driver
public DatabaseConnection(){
try{
Class.forName("org.postgresql.Driver");
establishConnection();
} catch (ClassNotFoundException ce) {
System.out.println("Could not load jdbc Driver: ");
ce.printStackTrace();
}
}
public Connection establishConnection() {
// TODO Auto-generated method stub
try{
connection = DriverManager.getConnection(url, uname, pword);
} catch (SQLException e){
System.out.println("Could not connect to database: ");
e.printStackTrace();
}
return connection;
}
}
public class SingletonConnection {
private static DatabaseConnection con;
public SingletonConnection(){}
public static DatabaseConnection instance(){
assert con == null;
con = new DatabaseConnection();
return con;
}
}
This is my user table created by Pgadmin3 (hence the ugly upper cases):
CREATE TABLE "user"
(
id serial NOT NULL,
"userRoleId" integer NOT NULL,
"employeeId" bigint NOT NULL,
"subjectId" bigint NOT NULL,
username text NOT NULL,
cryptpwd text NOT NULL,
"userStatusId" integer NOT NULL,
md5pwd text NOT NULL,
CONSTRAINT pk_user PRIMARY KEY (id),
CONSTRAINT "subjectId" FOREIGN KEY ("subjectId")
REFERENCES subject (id) MATCH FULL
ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT user_employee_id FOREIGN KEY ("employeeId")
REFERENCES employee (id) MATCH FULL
ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT "user_userRole_id" FOREIGN KEY ("userRoleId")
REFERENCES "userRole" (id) MATCH FULL
ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT "user_userStatus_id" FOREIGN KEY ("userStatusId")
REFERENCES "userStatus" (id) MATCH FULL
ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT "unique_user_userName" UNIQUE (username)
)
Since this application will be run on many machines in a local network, I would like to have only a single connection instance per specific user. That is, if userA logs in from one machine, and userA logs in from another machine moments later, notifications should appear on both machines with the second log in having the option to continue with the connection - in which case, the existing connection is dropped/lost.
I imagine I'd have to add a new column (logged_on boolean) in my user table ... in which case the second log in is handled by finding the value of logged_on and acting appropriately. My question is, how then will I be able to close the first connection? How can I maintain a maximum of one connection - per user - at database level?
Ok, this is what I'm working on. Surprisingly, I was thinking of something along the lines you mentioned Zamezela ... I haven't got it working yet, but I think this should work.
My user table:
CREATE TABLE "user"
(
id serial NOT NULL,
"userRoleId" integer NOT NULL,
"employeeId" bigint NOT NULL,
"subjectId" bigint NOT NULL,
username text NOT NULL,
cryptpwd text NOT NULL,
"userStatusId" integer NOT NULL,
md5pwd text NOT NULL,
"loggedIn" boolean NOT NULL DEFAULT false,
CONSTRAINT pk_user PRIMARY KEY (id),
CONSTRAINT "subjectId" FOREIGN KEY ("subjectId")
REFERENCES subject (id) MATCH FULL
ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT user_employee_id FOREIGN KEY ("employeeId")
REFERENCES employee (id) MATCH FULL
ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT "user_userRole_id" FOREIGN KEY ("userRoleId")
REFERENCES "userRole" (id) MATCH FULL
ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT "user_userStatus_id" FOREIGN KEY ("userStatusId")
REFERENCES "userStatus" (id) MATCH FULL
ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT "unique_user_userName" UNIQUE (username)
)
I've created a table that records each and every user login. Will help track down on user activity:
CREATE TABLE "userLoginHistory"
(
"userId" integer NOT NULL,
_datetime timestamp without time zone NOT NULL,
hostname text NOT NULL,
"osUsername" text NOT NULL,
id bigserial NOT NULL,
CONSTRAINT "pk_userLoginHistory" PRIMARY KEY (id),
CONSTRAINT "userLoginHistory_user_id" FOREIGN KEY ("userId")
REFERENCES "user" (id) MATCH FULL
ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE
)
I now have three main Stored functions thus far ... may add on to them tomorrow. Getting late.
First one involves requesting for a user login. This returns the user id, role, whether someone is logged on on this user account, and whether this user is active:
create type userLoginRequestReturnType as
(
userId integer, -- user.id
userRoleId integer, -- user.roleId
loggedIn boolean, -- user.loggedIn
userActive boolean -- whether user is active
);
CREATE OR REPLACE FUNCTION "user_login_request"(usernameIn text, passwordIn text)
returns setof userLoginRequestReturnType as
$$
declare
user_Id integer;
user_RoleId integer;
user_StatusId integer;
user_loggedIn boolean;
user_Active boolean;
sql text;
begin
user_Active = false;
select into user_Id, user_RoleId, user_StatusId, user_loggedIn id, "userRoleId", "userStatusId", "loggedIn" from "user" where username = usernameIn and cryptpwd = crypt(passwordIn, cryptpwd);
if (user_id > 0) then -- record found
select into user_Active "user_is_active"(user_StatusId);
else
user_id = 0;
user_RoleId = 0;
user_loggedIn = false;
user_Active = false;
end if;
sql = 'select ' || user_Id || ', ' || user_RoleId || ', ' || user_loggedIn || ', ' || user_Active ||';';
return query execute sql;
end;
$$ language 'plpgsql';
This is passed to the front end. If user_loggedIn is true, and all the other attributes support a successful log in, then the front end will notify the user that there is an existing connection, and whether to continue (disconnecting the existing connection). If it is false, then it just continues (without any prompt) to this function:
CREATE OR REPLACE FUNCTION "user_login_complete"(userIdIN integer, hostnameIN text, osUsernameIN text)
returns bigint as
$$
declare
currentTime timestamp without time zone;
userLoginHistoryId bigint;
begin
-- update user.loggedIn
update "user" set "loggedIn" = true where id = userIdIN;
-- insert into userLoginHistory
currentTime = NOW()::timestamp without time zone;
insert into "userLoginHistory" ("userId", _datetime, hostname, "osUsername") values (userIdIN, currentTime, hostnameIN, osUsernameIN);
select into userLoginHistoryId currval('"userLoginHistory_id_seq"');
return userLoginHistoryId;
end;
$$ language 'plpgsql';
The userLoginHistoryId is stored on the front end, since I'm using an MVC architecture for my Java Swing project, my abstract Model Class will call the following function in its constructor. I have taken your advice and will close the connection in each method.
-- function to check if the current logged in session is the last one recorded in database
-- to be run before each connection to the database as per userId
-- new userLoginHistoryId must be inserted into table userLoginHistory, and the id PK value stored in the front end
--
-- returns: true, if current session is the last session recorded in table userLoginHistory for this user_autosuggest_by_ID
-- : false, if another login session has been recorded.
-- MUST BE EXECUTED BEFORE EACH AND EVERY DATABASE TRANSACTION!!!!!
CREATE OR REPLACE FUNCTION "user_login_session_check"(userIdIN integer, userLoginHistoryIdIN bigint)
returns boolean as
$$
declare
results boolean;
userLoginHistoryId bigint;
begin
results = true;
select into userLoginHistoryId id from "userLoginHistory" where "userId" = userIdIN ORDER BY id DESC LIMIT 1;
if (userLoginHistoryIdIN = userLoginHistoryId) then
results = true;
else
results = false;
end if;
end;
$$ language 'plpgsql';
Will test tomorrow and hopefully it works fine. Please feel free to comment.
Thanks.
#greatkalu your problem is much deeper and very hard achievable, I will suggest you some approach: when user log in you should update two fields(last_access_timestamp, computer_id) and for every access to the database you should update last_access_timestamp. computer_id and last_access_time should be valid maybe 1 hour or less depends of the use of the application. when other person tries to login with same user_id then if now() - 1 hour < last_access_timestamp then that user should not be grant access.
computer_id is generated from application and for every computer should be unique and always generated same computer_id.
I hope this will help

Categories