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

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.

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.

Data insertion using auto incremented column as primary key

I have two tables whereby the primary key(foreign key on the other table) is auto incremented at run time (using TOAD for mysql).
How can I insert data into the two tables at the same time using a transaction.
This is the ddl for the first table:
CREATE TABLE `suspendedsales` (
`SID` int(11) NOT NULL AUTO_INCREMENT,
`SequenceNo` int(11) NOT NULL DEFAULT '0',
`ProductCode` varchar(100) DEFAULT NULL,
`ItemName` varchar(100) DEFAULT NULL,
`Quantity` int(11) DEFAULT NULL,
`Discount` double DEFAULT NULL,
`ItemCost` double DEFAULT NULL,
PRIMARY KEY (`SID`,`SequenceNo`),
CONSTRAINT `SIDFKey` FOREIGN KEY (`SID`) REFERENCES `suspendedsalesdetails` (`SID`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
The ddl for the second table:
CREATE TABLE `suspendedsalesdetails` (
`SID` int(11) NOT NULL DEFAULT '0',
`Date` date DEFAULT NULL,
`Total` double DEFAULT NULL,
PRIMARY KEY (`SID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
N.B: The major challenge would be to get the auto-incremented key value from on the primary key to be inserted into the other table at run time.
Thanks in anticipation.
If your database is a MySql database you can insert a record in the first table use the following function
SELECT LAST_INSERT_ID();
to get the last inserted id and you can use it in the second insert. Commit all only after the second insert
How about this:
private void insert() {
OraclePreparedStatement statement = null;
try {
Connection dbConnection = getConnection();
statement = dbConnection.createStatement();
String insertToSuspendedsales = "insert into suspendedsales (SequenceNo, ProductCode,ItemName,Quantity,Discount,ItemCost) "
+ "values(:segNo, :prodNo, :itmeName, :quantity, :discount, :itemCost) returning SID into ?";
statement.setIntAtName("segNo", intValue);
....
int id = statement.registerReturnParameter(1, OracleTypes.INTEGER)
statement.executeUpdate(insertToSuspendedsales);
String insertToSuspendedsalesdetails = "insert into suspendedsalesdetails (SID, Date, Total) "
+ "values(:sid, :date, :total) returning SID into ?";
statement.setIntAtName("sid", id);
....
statement.executeUpdate(insertToSuspendedsalesdetails);
} catch (SQLException ex) {
ex.printStackTrace();
//rollback
} finally {
//close Connection
}
}

Compare an SQL file to an existing database table with Java

I am writing a bit of Java (1.7) code to test a given database table against a given sql file. What I would like is a way to turn my sql file into a java object, then test the db field names and field types are the same as the file backed object.
An example sql file looks like this:
create table foo (
id int not null auto_increment,
term_id varchar(128) not null,
term_name varchar(255) not null,
parent_id varchar(128) not null,
parent_name varchar(255),
top_term_flag varchar(5),
primary key (id)
);
create index foo_pn on foo ( parent_name );
create index foo_ttf on foo ( top_term_flag );
And the part of my Java program to do this check looks like this:
// Step 1, confirm the table exists
// Database and table tests
DatabaseMetaData dbm = connection.getMetaData();
// check if "this.dbtable" exists.
// The ToUpperCase covers Oracle
ResultSet tables = dbm.getTables(null, null, this.dbtable.toUpperCase(), null);
if (tables.next()) {
// Table exists
log.info("Table: {} exists!", this.dbtable);
// Step 2, get each field and test against the file
ResultSet columns = dbm.getColumns(null, null, this.dbtable, null);
while ( columns.next()) {
String name = columns.getString(4); // this gets the column name
-> Now what? <-
}
}
I've looked at Spring JDBCTestUnit and Flyway, but they don't seem to provide the functionality I need.
Thank you.
Update:
I understand I can also use Hibernate to generate my Java classes that represent my sql file and then test the DB table against those. Does any one have a sample for how to get this done?
Using JSqlParser 0.8.8 from https://github.com/JSQLParser/JSqlParser.
Here is a parsing example to get column names, table name, types. As a result you get a hierarchy of java objects from your sqls.
public class CheckSQLs {
public static void main(String[] args) throws JSQLParserException {
String sqls = "create table foo (\n"
+ " id int not null auto_increment,\n"
+ " term_id varchar(128) not null,\n"
+ " term_name varchar(255) not null,\n"
+ " parent_id varchar(128) not null,\n"
+ " parent_name varchar(255),\n"
+ " top_term_flag varchar(5),\n"
+ " primary key (id)\n"
+ ");\n"
+ "create index foo_pn on foo( parent_name );\n"
+ "create index foo_ttf on foo ( top_term_flag );";
for (String sql : sqls.split(";")) {
Statement parse = CCJSqlParserUtil.parse(sql);
System.out.println(parse);
if (parse instanceof CreateTable) {
CreateTable ct = (CreateTable)parse;
System.out.println("table=" + ct.getTable().getFullyQualifiedName());
for (ColumnDefinition colDef : ct.getColumnDefinitions()) {
System.out.println("column=" + colDef.getColumnName() + " " + colDef.getColDataType() + " " + colDef.getColumnSpecStrings());
}
}
}
}
}
This runs with the output:
CREATE TABLE foo (id int not null auto_increment, term_id varchar (128) not null, term_name varchar (255) not null, parent_id varchar (128) not null, parent_name varchar (255), top_term_flag varchar (5), primary key (id))
table=foo
column=id int [not, null, auto_increment]
column=term_id varchar (128) [not, null]
column=term_name varchar (255) [not, null]
column=parent_id varchar (128) [not, null]
column=parent_name varchar (255) null
column=top_term_flag varchar (5) null
Now you could use this object to validate against your database.
If the SQL file syntax doesn't vary much from your example, you could write a simple parser to read the file and generate your java object: table plus list of fields/types and indexes
"tablename" always comes after "create table"
the field names and types always come after that
indexes after that
Or there are parsers available:
jsqlparser
http://jsqlparser.sourceforge.net/
Other questions on this site cover some of the same ground
SQL parser library for Java

JDBC Exception when enter data in the table with foreign keys

When I enter data with my java program (simple dictionary ) it throws an error:
MySQLIntegrityConstraintViolationException: Cannot add or update a
child row: a foreign key constraint fails (singlehaw.card,
CONSTRAINT card_ibfk_1 FOREIGN KEY (wordId) REFERENCES word
(wordId))
But when I enter data through query in command prompt I don't face any problem.
here I post my method:
public boolean insert(Card card) {
Connection connection = MySqlUtils.getInstance().getConnection();
PreparedStatement statement = null;
ResultSet resultSet = null;
int cardId = -1;
try {
String INSERT_INTO_TABLE_CARD_QUERY = "INSERT INTO "
+ TBL_CARD + " ("
+ STATUS + ", "
+ RATING + ", "
+ INSERT_TIME + ", "
+ DIC_ID + ", "
+ WORD_ID
+ ") VALUES (?,?,NOW(),?,?)";
statement = connection.prepareStatement(INSERT_INTO_TABLE_WORDS_QUERY, Statement.RETURN_GENERATED_KEYS);
statement.setString(1, card.getStatus().name());
statement.setInt(2, card.getRating());
statement.setInt(3, card.getDictionaryId());
statement.setInt(4, card.getWordId());
statement.execute();
// get last inserted id
resultSet = statement.getGeneratedKeys();
if (resultSet.next())
cardId = resultSet.getInt(1);
} catch (SQLException e) {
e.printStackTrace();
return false;
} finally {
try {
if (connection != null)
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
card.setCardId(cardId);
return true;
}
and also scripts of creating tables:
CREATE TABLE dictionary (
dictionaryId SERIAL,
dictionary VARCHAR(128) NOT NULL,
PRIMARY KEY (dictionaryId)
) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE word (
wordId SERIAL,
word VARCHAR(255) NOT NULL UNIQUE,
transcription VARCHAR(255),
PRIMARY KEY (wordId)
) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE card (
cardId SERIAL,
status ENUM ('EDIT', 'POSTPONED', 'TO_LEARN', 'LEARNT') NOT NULL DEFAULT 'TO_LEARN',
rating TINYINT DEFAULT '0' NOT NULL,
insert_time TIMESTAMP DEFAULT NOW(),
update_time TIMESTAMP,
dictionaryId BIGINT UNSIGNED NOT NULL,
wordId BIGINT UNSIGNED NOT NULL,
PRIMARY KEY (cardId),
FOREIGN KEY (wordId) REFERENCES word (wordId),
FOREIGN KEY (dictionaryId) REFERENCES dictionary (dictionaryId) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Perhaps, the fact your wordID fields on the tables have different data types is affecting your program. SERIAL is an alias for Bigint. Idea discarded.
Print somwehere in the logs the actual statement being executed. Maybe there's something that's not being included.
Thnx guys a lot. Understood many things from this topic. Right now the problem has gone. The problem was due to populating tables via JUnit tests and because of maven my tests gone in a wrong order so it was difficult to recognize the real problem.
You can switch off your constraints ,execute your query, and switch constraints on.
SET FOREIGN_KEY_CHECKS=0;
... here is your sql ...
SET FOREIGN_KEY_CHECKS=1;

How to get super table information in java?

My database had a lot of parent and child tables.The tables contains the foreign key which has the link with the parent table.I wants to get the information of parent table of the child table using java?How can I achieve that?
For ex,consider the student and mark table,
The student table contains the information like studentID,name.
studentID-Primary key
The marks table contains the markId,studentId,Sub1,sub2,sub3 etc
markId-Primarykey
studentID-Foreignkey refers Student table
My table creation queries are,
CREATE TABLE `Student12` (
`studentId` SMALLINT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
PRIMARY KEY (`studentId`)
)
ENGINE = InnoDB;
CREATE TABLE `Marks` (
`markId` SMALLINT NOT NULL AUTO_INCREMENT,
`subject1` SMALLINT NOT NULL,
`subject2` SMALLINT NOT NULL,
`studentId` SMALLINT NOT NULL,
PRIMARY KEY (`markId`),
CONSTRAINT `FK_Marks_Student` FOREIGN KEY `FK_Marks_Student` (`studentId`)
REFERENCES `Student12` (`studentId`)
ON DELETE RESTRICT
ON UPDATE RESTRICT
)
ENGINE = InnoDB;
If I give the mark table name as input, how can I get its parent or super table name student and information about student table?Any help should be appreciable.
It totally depends on the way tables are created. Foreign keys are not mandatory to create, they could be a simple column in one table with no explicit relationship to the other table. If you are very sure that the links are created explicitly (the foreign keys are defined) then you could use information_schema. But if there is no foreign key defined (which is true in most of the databases I have seen), then there is no way for you to find the links inside the database. You have to look into the code (if there is any available) and try to find a clue.
The JDBC DatasetMetaData interface provides a couple of methods that may help. (The following text is copied from the javadoc.
ResultSet getExportedKeys(String catalog, String schema, String table)
Retrieves a description of the foreign key columns that reference the given table's primary key columns (the foreign keys exported by a table).
ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable, String foreignCatalog, String foreignSchema, String foreignTable)
Retrieves a description of the foreign key columns in the given foreign key table that reference the primary key or the columns representing a unique constraint of the parent table (could be the same or a different table).
Of course, these can only work if the relevant columns have been declared as foreign keys in the SQL table DDL.
You can use the DatabaseMetaData to retrieve informations about foreign keyes
and the referenced Tables. Im not sure if it works with all kinds of MySql Tables.
The principle is to use the follwing code (not tested) to retrieve information about the super tables
ResultSet rs = null;
DatabaseMetaData dm = conn.getMetaData( );
// get super tables of table marks
ResultSet rs = dm.getSuperTables( null , null, "marks" );
while( rs.next( ) ) {
System.out.println(String.format("Table Catalog %s", rs.getString("TABLE_CAT") );
System.out.println(String.format("Table Schema %s", rs.getString("TABLE_SCHEM") );
System.out.println(String.format("Table Name %s", rs.getString("TABLE_NAME") );
System.out.println(String.format("Table Name %s", rs.getString("SUPERTABLE_NAME") );
}
You can use thes informations to get additional informations about the referenced table
and the foreigen and referenced primary keys:
ResultSet rs = dm.getCrossReference( null , null , "student" , null , null , "marks" );
System.out.println(String.format("Exported Keys Info Table %s.", "marks"));
while( rs.next( ) ) {
String pkey = rs.getString("PKCOLUMN_NAME");
String ptab = rs.getString("PKTABLE_NAME");
String fkey = rs.getString("FKCOLUMN_NAME");
String ftab = rs.getString("FKTABLE_NAME");
System.out.println("primary key table = " + ptab);
System.out.println("primary key = " + pkey);
System.out.println("foreign key table = " + ftab);
System.out.println("foreign key = " + fkey);
}
And finally you can retrieve the information about the super table by
ResultSet rs = dm.getTables(null,null,"student" ,null);
System.out.println("Table name:");
while (rs.next()){
String table = rs.getString("TABLE_NAME");
System.out.println(table);
}

Categories