JavaFX Sqlite Insert with Foreign Key - sqlite

I am currently learning JavaFX and Sqlite.
I have an Sqlite Database which I built with MySQL manager, there are already foreign key rules etc.
For example user and adress:
CREATE TABLE "Benutzer" ("Benutzername" TEXT PRIMARY KEY NOT NULL , "Vorname" VARCHAR, "Nachname" VARCHAR, "Email" TEXT UNIQUE , "Passwort" TEXT, "AdresseID" INTEGER, FOREIGN KEY(AdresseID) REFERENCES Adresse(AdresseID))
CREATE TABLE "Adresse" ("AdresseID" INTEGER PRIMARY KEY NOT NULL , "Land" VARCHAR, "Stadt" VARCHAR, "Straße" TEXT, "Hausnr." INTEGER)
I connected the database to my JavaFX application, now I am trying to create the register function, so a new user is on an fxml template where he can fill in "Benutzername", "Vorname" etc. and his adress "Land", "Stadt" etc.
Here is the form:
Adding these values to the database works, but I do not have an idea how to tell javaFX that this current user which is inserted has to take the current adress which is inserted (its AdressID) as foreign key.
User is inserted without foreign key:
I was reseaching and found things like
mysql_insert_id returns the last auto-increment value generated by the database connection currently in use.
But I dont know how to access it.
Thats my model which I use to fill in the data into my database:
public class RegisterModel {
Connection conection;
// Konstruktor
public RegisterModel() {
conection = SqliteConnection.Connector();
// Wenn die Verbindung nicht erfolgreich ist, dann App schließen
if (conection == null) {
System.out.println("connection not successful");
System.exit(1);
}
}
public boolean isDbConnected() {
try {
return !conection.isClosed();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
}
public boolean RegisterUser(String user_benutzername, String user_vorname, String user_nachname, String user_email,
String user_passwort, String adress_land, String adress_stadt, String adress_strasse,
String adress_hausnummer) throws SQLException {
PreparedStatement preparedStatement = null;
PreparedStatement preparedStatement_for_adress = null;
// or ignore besprechen
String query = "insert or ignore into Benutzer (Benutzername, Vorname, Nachname, Email, Passwort) values(?,?,?,?,?)";
String query_adress = "insert into Adresse (Land, Stadt, Straße, 'Hausnr.') values(?,?,?,?)";
try {
preparedStatement = conection.prepareStatement(query);
preparedStatement.setString(1, user_benutzername);
preparedStatement.setString(2, user_vorname);
preparedStatement.setString(3, user_nachname);
preparedStatement.setString(4, user_email);
preparedStatement.setString(5, user_passwort);
System.out.println("Benutzer wurde eingefuegt");
preparedStatement_for_adress = conection.prepareStatement(query_adress);
preparedStatement_for_adress.setString(1, adress_land);
preparedStatement_for_adress.setString(2, adress_stadt);
preparedStatement_for_adress.setString(3, adress_strasse);
preparedStatement_for_adress.setString(4, adress_hausnummer);
System.out.println("Adresse wurde eingefügt");
preparedStatement.executeUpdate();
preparedStatement_for_adress.executeUpdate();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
preparedStatement.close();
preparedStatement_for_adress.close();
}
}
}
I think there must be a 3rd query which takes the AdressID of the current adress and assigns it to the current user as his adress? So thats the interessting part:
String query = "insert or ignore into Benutzer (Benutzername, Vorname, Nachname, Email, Passwort) values(?,?,?,?,?)";
String query_adress = "insert into Adresse (Land, Stadt, Straße, 'Hausnr.') values(?,?,?,?)";

You should insert the Address first with a PreparedStatement.
Retrieve the ID (last inserted ID) of the Address, see Java PreparedStatement retrieving last inserted ID
Now insert the User with the AddressId stated in step 2. So you have to include the AddressId column in the user INSERT INTO statement.
Your user insert query should become:
String query = "insert or ignore into Benutzer (Benutzername, Vorname, Nachname, Email, Passwort, AddressId) values(?,?,?,?,?,[put last_inserted_id here)";

Related

How to write transaction in Mariadb?

using query " BEGIN; INSERT INTO employee (id, name) VALUES (:id,:name); COMMIT ;" to commit the transaction through java code and additionally setting id and name parameters but getting below error.
"Caused by: java.sql.SQLSyntaxErrorException: (conn=812) You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'INSERT INTO employee (id, name) VALUES (150,'150_abc'); COMMIT' at line 1
have tried with belwo query:
start transaction; INSERT INTO employee (id, name) VALUES (:id,:name); COMMIT ;
using MariaDb version 10.7.3
you should try the following :
MOST IMPORTANT TO CONSIDER, IS TO SET THE AUTOCOMMIT TO FALSE, otherwise MariaDB will refuse not automatic transaction management.
import java.sql.*;
public class App {
public static void main(String[] argv) {
try (Connection conn = DriverManager.getConnection("jdbc:mariadb://192.0.2.1:3306?user=db_user&password=db_user_password")) {
conn.setAutoCommit(false);
try {
try (PreparedStatement prep = conn.prepareStatement("INSERT INTO test.accounts(first_name, last_name, email, amount) VALUES (?, ?, ?, ?)")) {
prep.setString(1, "John");
prep.setString(2, "Smith");
prep.setString(3, "john.smith#example.com");
prep.setDouble(4, 900.00);
prep.executeQuery();
}
try (PreparedStatement prep = conn.prepareStatement("UPDATE test.accounts SET amount = ? WHERE email = ?")) {
prep.setDouble(1, 1000.00);
prep.setString(2, "john.smith#example.com");
prep.executeQuery();
}
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
conn.rollback();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

JavaFX Saving editable TableView to SQL

I have created a two column editable TableView which the user can edit and change the data thats inside each cell. Now my question is, once the user has changed some data around in each cell, how do I then save this data or print it out in a way to add to an SQL query like this example below
INSERT INTO table_name
VALUES (Value from table,Value from table,Value from table,...);
//Editable cell
PriceColumn.setCellFactory(TextFieldTableCell.forTableColumn());
PriceColumn.setOnEditCommit(
new EventHandler<CellEditEvent<NewCustomerList, String>>() {
#Override
public void handle(CellEditEvent<NewCustomerList, String> t) {
((NewCustomerList) t.getTableView().getItems().get(
t.getTablePosition().getRow())).setPrice(t.getNewValue());
}
}
);
You could do this by getting the required values and then passing them onto the DAO class to execute the query on the DB. Example follows-
PriceColumn.setOnEditCommit(
new EventHandler<CellEditEvent<NewCustomerList, String>>() {
#Override
public void handle(CellEditEvent<NewCustomerList, String> t) {
((NewCustomerList) t.getTableView().getItems().get(t.getTablePosition().getRow())).setPrice(t.getNewValue());
String newPrice = t.getNewValue();
String uniqueIdentifier = t.getRowValue().getUniqueIdentifier(); //Unique identfier is something that uniquely identify the row. It could be the name of the object that we are pricing here.
daoObj.updatePrice(newPrice, uniqueIdentifier); //Call DAO now
}
}
);
And somewhere in the deep dark jungles of DAO class,
private final String updateQuery = "UPDATE <TABLE_NAME> SET <PRICE_COLUMN> = ? WHERE <UNIQUE_COLUMN> = ?"; //If you require multiple columns to get a unique row, add them in the where clause as well.
public void updatePrice(String newPrice, String uniqueIdentifier) {
PreparedStatement ps = con.prepareStatement(updateQuery); //con is the connection object
ps.setString(1,uniqIdentifier); //if a string
ps.setString(2,newPrice); //if a string
ps.executeQuery();
}
If this is not what you were expecting, then can you please clarify your requirement?

retrieve a row of data from documentum via DQL

I have a list of users in my list view which is populated by retrieving data from documentum . If I click on any row of this least (each row represent one user) I should be able to see all of their information listed down .(This is my problem )
public void selectedItemFromListView(){
selected = lwAllUserGrp.getSelectionModel().getSelectedItem();
System.out.println(selected);
String query =" select * from dm_user where user_name = '#aclName'" ;
String test = query.replace("#aclname", selected);
GetDataWithDqlProfile(_session , query , "user_login_name" , "user_address" , "user_state" );
System.out.println(user.getAddress());
System.out.println(user.getState());
System.out.println(user.getUsername());
}
if I click on a row of list view I can successfully see who is selected and I need to retrieve all the other attributes of that username (same person) from documentum via DQL .
private void GetDataWithDqlProfile(IDfSession session, String Query, String username , String address , String state ) {
try {
IDfQuery UpdateQuery = new DfQuery();
UpdateQuery.setDQL(Query);
IDfCollection col = UpdateQuery.execute(_session, IDfQuery.DF_QUERY);
user.setAddress(col.getString(username));
user.setUsername(col.getString(address));
user.setState(col.getString(state));
col.close();
} catch (Exception e) {
Alert alert = new Alert(Alert.AlertType.ERROR, e.getMessage());
alert.showAndWait();
Logs.WriteLog(LoginController.Repository + ",User:" + LoginController.Username, "DQL Query", e.toString());
e.getStackTrace();
}
and my output is :
User's name
null
null
null
I've tried the DQL query in DQL tester and it works well
In order to fetch rows from IDfCollection you have to call next() on the collection object. This method both advances to the next row and returns a boolean if successful. Use a boolean test (e.g., while or if) to iterate, like this:
IDfCollection col = UpdateQuery.execute(_session, IDfQuery.DF_QUERY);
if (col.next()) {
user.setAddress(col.getString(username));
user.setUsername(col.getString(address));
user.setState(col.getString(state));
}
col.close();
The iteration is necessary even if the collection contains only one row. In other words, you need to manually advance to the first row.
1) As #eiviamu already mentioned, you have to call IDfCollection.next() to get the next row.
2) Your code, among other problems, has one documentum-related: closing of collection must happen always in finally block.
Otherwise you can get unclosed collection which might lead to memory leaks and weird application behavior (e.g. if I'm not mistaken there are 9 simultaneous open collections are allowed for one DCTM session by default, and if you exceed this limit an exception will be thrown)
For those of you referring to this question later here is how I solved the problem :
public ArrayList<User> GetDataWithDqlpro(IDfSession session, String Query, String username , String state , String address) {
try {
IDfQuery UpdateQuery = new DfQuery();
UpdateQuery.setDQL(Query);
IDfCollection col = UpdateQuery.execute(_session, IDfQuery.DF_QUERY);
while (col.next()) {
list.add( new User(col.getString(username),col.getString(address) , col.getString(state)));
}
col.close();
}catch (Exception e) {
Alert alert = new Alert(Alert.AlertType.ERROR, e.getMessage());
alert.showAndWait();
Logs.WriteLog(LoginController.Repository + ",User:" + LoginController.Username, "DQL Query", e.toString());
e.getStackTrace();
}
return (ArrayList<User>) list;
}
public void selectedItemFromListView(){
selected = lwAllUserGrp.getSelectionModel().getSelectedItem();
System.out.println(selected);
String Query = "select user_login_name , user_state , user_address from dm_user where user_login_name ='#aclname'";
Query = Query.replace("#aclname",selected );
ArrayList<User> allUserNames = GetDataWithDqlpro(_session, Query, "user_login_name","user_address","user_state");
for (int i = 0 ; i <= allUserNames.size()-1 ; i++ ){
if (selected.compareToIgnoreCase(allUserNames.get(i).getUsername() ) == 0){
System.out.println(allUserNames.get(i).getState() );
System.out.println(allUserNames.get(i).getAddress() );
System.out.println(allUserNames.get(i).getUsername() );
}
}
}
Worth mentioning that I have a class called User with constructor and get and set methods
I hope it will help some one :)

Why am I getting "Invalid object name 'FinishedMappings'." here?

I call
public bool CheckIfFinished ( Guid pid, int sid )
{
// pid: guid corresponding to partner
// sid: survey id
bool finished = false;
using (SqlCommand cmd = new SqlCommand("CheckIfFinished", this._Conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#pid", pid);
cmd.Parameters.AddWithValue("#sid", sid);
this._Conn.Open();
using ( SqlDataReader dataReader = cmd.ExecuteReader() )
{
while (dataReader.Read())
{
finished = dataReader.GetByte(0) == 1 ? true : false;
}
}
this._Conn.Close();
}
return finished;
}
which calls the sproc
GO
-- Create sproc for returning whether a partner has marked their survey as finished
CREATE PROCEDURE CheckIfFinished
#pid UNIQUEIDENTIFIER,
#sid INT
AS
BEGIN
SELECT 1 FROM FinishedMappings WHERE partner_id=#pid AND survey_id=#sid
END
which uses the table FinishedMappings which does exist because it was defined with
CREATE TABLE FinishedMappings (
partner_id UNIQUEIDENTIFIER,
survey_id INT,
PRIMARY KEY (partner_id,survey_id),
FOREIGN KEY (partner_id) REFERENCES Partners(id),
FOREIGN KEY (survey_id) REFERENCES Surveys(id)
);
right above the sproc. Why am I getting the error?
If the table was created using a different user to the one that you are executing the sp with then a fully qualified name could be needed. I would check this first as dimasun suggested in his first reply.
Also check to see if you can execute the sp directly in SQL management studio. If this doesn't work then you can focus on the code in the sp

Custom RoleProvider: Can't insert record in UsersInRole Table

I have implemented a LINQ to SQL based RoleProvider, when I assign role to a user following exception is thrown while AddUsersToRoles method is called. I have defined a composite primary key userid & roleId on this table, it still throwing this exception:
Can't perform Create, Update or Delete
operations on 'Table(UsersInRole)'
because it has no primary key.
My LinQ to SQL implementation of AddUsersToRoles method is as follows. It breaks at db.UsersInRoles.InsertOnSubmit(userInRole);
using (RussarmsDataContext db = new RussarmsDataContext())
{
List<UsersInRole> usersInRole = new List<UsersInRole>();
foreach (string username in usernames)
{
foreach (string rolename in rolenames)
{
UsersInRole userInRole = new UsersInRole();
object userId = ProvidersUtility.GetUserIdByUserName(username,applicationName);
object roleId = ProvidersUtility.GetRoleIdByRoleName(rolename,applicationName);
if (userId != null && roleId != null)
{
userInRole.UserId = (Guid)userId;
userInRole.RoleId = (Guid)roleId;
db.UsersInRoles.InsertOnSubmit(userInRole);
}
}
}
try
{
// db.UsersInRoles.InsertAllOnSubmit(usersInRole);
db.SubmitChanges();
}
catch (ChangeConflictException)
{
db.ChangeConflicts.ResolveAll(RefreshMode.OverwriteCurrentValues);
db.SubmitChanges();
}
}
Any help will be appreciated.
Thanks.
LINQ to SQL does not natively support many to many... the joining table has to have two foreign key columns PLUS 1 primary key column with the IDENTITY attribute.

Resources