Update foreign key in Qt QSqlRelationalTableModel - qt

I'm coding in python (PySide2), but the overall concept concerns the Qt Framework.
Here are two tables of mine:
Table "recordings":
| Column | Type |
| -------- | -------------------|
| id | int (primary key) |
| param1 | int |
| param2 | int |
| ... | int |
| paramN | int |
Table "analyzed_recs":
| Column | Type |
| -------- | -------------------|
| id | int (primary key) |
| rec_id | int (foreign key) | <-- Points to recordings.id
| paramN | int |
I need in my program to display param1 and param2 from the former. In Qt I used a QSqlRelationalTable to fulfill this objective:
def _init_db_models(self):
self.analyzed_recs_sql_model = QSqlTableModel(self, self.db)
self.analyzed_recs_sql_model.setTable("analyzed_recs")
rec_id = self.analyzed_recs_sql_model.fieldIndex('rec_id')
self.analyzed_recs_sql_model.setRelation(rec_id, QSqlRelation("recordings", "id", "param1"))
self.analyzed_recs_sql_model.setRelation(rec_id, QSqlRelation("recordings", "id", "param2"))
self.analyzed_recs_sql_model.select()
self.analyzed_data_table.setModel(self.analyzed_recs_sql_model)
This code works fine in displaying the desired fields.
However, when it comes to update a record in analyzed_recs:
record = self.analyzed_recs_sql_model.record()
record.remove(record.indexOf("id"))
record.setValue("rec_id", self.current_rec_id)
record.setValue("param1", self.param1)
record.setValue("param2", param2)
self.analyzed_recs_sql_model.insertRecord(-1, record)
self.analyzed_recs_sql_model.submitAll()
The column rec_id is not set (NULL) into the table (the other params are correctly inserted into the table).
On the contrary, if I avoid using QSqlRelationalTableModel and take QSqlTableModel instead, the insertion is performed correctly (as I expected), but I lose the INNER JOIN display feature.
I was thinking as a work around to create two distinct models, a QSqlRelationalTableModel only for displaying and a QSqlTableModel only for editing the data. However I don't like the extra workload of syncing the two.
I'm sure there is a Qt feature to achieve this, but unfortunately I'm missing it.
Any suggestion?

I've had the same problem using PYQT.
The record object returned by calling record() method has no fields named 'rec_id' because the QSqlRelationalTableModel changes it with the referenced field name 'param1'. We can verify the field names using:
fieldcount = record.count()
for i in range(fieldcount):
logging.info("field %s %s", i, record.fieldName(i))
so we need to add the field before assigning it:
record = self.analyzed_recs_sql_model.record()
record.remove(record.indexOf("id"))
record.append(QSqlField("rec_id"))
record.setValue("rec_id", self.current_rec_id)

Related

Loop import XML files

I'm using MariaDB to import some files in XML.
Here is a snippet of the code I'm using:
CREATE TABLE invoices (
InvoiceNumber VARCHAR(20),
InvoiceStatus CHAR (1),
InvoiceDate CHAR (10),
Period CHAR (2)
)
;
DROP TABLE if EXISTS temptbl;
create table temp02 (
InvoiceNumber VARCHAR(20) xpath='InvoiceNo',
InvoiceStatus CHAR(1) xpath='DocumentStatus/InvoiceStatus',
InvoiceDate CHAR (10) xpath='InvoiceDate',
Period CHAR (2) xpath='Period'
)
engine=CONNECT table_type=XML file_name='..\\importmaridb\\month01.xml'
tabname='AuditFile' option_list='rownode=SourceDocuments/SalesInvoices/Invoice';
INSERT INTO invoices
SELECT * FROM temptbl;
I then repeat 12x the code of importing to table "temptbl" changing only the file name to reflect the other months.
I would like to have a loop to iterate the files each time.
I believe part of the solution would be to create a table with the file names and an auto increment column, where I would loop through the numbers.
I've attempted to define a variable and substituting in the code, like file_name=#path. But MariaDB gives me an error a syntax error.
| VARIABLE_NAME | VARIABLE_VALUE | VARIABLE_TYPE | CHARACTER_SET_NAME |
+---------------+----------------+---------------+--------------------+
| path | ..\importmaridb| VARCHAR | utf8mb4 |
| | \month01.xml | | |
Can someone give me some pointers, and even if this is possible?

SQLite sort by position in a String [] , when that String [] is a field

I have a table like below in Room, in a Android application, I use Raw Query to get data. Can it be sorted by second value in array sorting_field?
---------------------------------------------
| id | other_fields | sorting_field |
---------------------------------------------
| 1001 | … | ["24","0.02","2"] |
---------------------------------------------
Initially I did the sorting part in Repository with Transformations.switchMap, inside the function a MutableLiveData> and applied Collections.sort.
It worked like a charm:
Collections.sort(list, (o1, o2) -> Double.compare(Double.valueOf(o1.sorting_field().get(positionInList)), Double.valueOf(o2.sorting_field().get(positionInList))));
After Paging implementation, I took the sorting logic out, moved to queries builder and here I am.

No content in javaFX tableview

So I checked the other No content in TableView but it was no help.
I have a database named ledger and I want to bring my transactions into view.
void buildData(){
final ObservableList<ObservableList<String>> data = null
try{
//ResultSet
ResultSet rs = sql.getTransactions(account.getValue().toString())
/**********************************
* TABLE COLUMN ADDED DYNAMICALLY *
**********************************/
for(int i=0 ; i<rs.getMetaData().getColumnCount(); i++){
//We are using non property style for making dynamic table
final int j = i
TableColumn col = new TableColumn(rs.getMetaData().getColumnName(i+1))
col.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<ObservableList,String>,ObservableValue<String>>(){
ObservableValue<String> call(TableColumn.CellDataFeatures<ObservableList, String> param) {
return new SimpleStringProperty(param.getValue().get(j).toString())
}
})
budgetTable.getColumns().addAll(col)
}
/********************************
* Data added to ObservableList *
********************************/
while(rs.next()){
//Iterate Row
ObservableList<String> row = FXCollections.observableArrayList()
for(int i=1 ; i<=rs.getMetaData().getColumnCount(); i++){
//Iterate Column
row.add(rs.getString(i))
}
println("Row [1] added "+row )
data?.add(row)
}
//FINALLY ADDED TO TableView
budgetTable.setItems(data)
}catch(Exception e){
e.printStackTrace()
System.out.println("Error on Building Data")
}
}
I have 5 columns in the database that do comeback and are added to the tableview. These are date, from_account, to_account, amount & notes:
mysql> show columns from ledger;
+--------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| version | bigint(20) | NO | | 1 | |
| date | datetime | NO | | NULL | |
| notes | varchar(35) | NO | | NULL | |
| amount | double | NO | | NULL | |
| from_account | varchar(19) | NO | | NULL | |
| to_account | varchar(55) | YES | | NULL | |
+--------------+-------------+------+-----+---------+----------------+
7 rows in set (0.45 sec)
I get no error or otherwise I would have a very good chance of solving it. At this point I don't know what the problem is. Just says "No content in table" upon build. The file is a groovy file so that's why it looks like python syntax.
Thank you in advance for your help, time and insights!
Be well!
I'm not very familiar with Groovy but I believe I know what the issue is. First off, you declare data as final and then assign null to it.
final ObservableList<ObservableList<String>> data = null;
This means it will be null when to go to set the items of the TableView. Basically, you're calling budgetTable.setItems(null). You would not normally reach this point because calling data.add(row) would throw a NullPointerException; except you don't use data.add(row) but rather data?.add(row). The ? here is the safe navigation operator.
The Safe Navigation operator is used to avoid a NullPointerException. Typically when you have a reference to an object you might need to verify that it is not null before accessing methods or properties of the object. To avoid this, the safe navigation operator will simply return null instead of throwing an exception...
See this question for more.
Given all this, simply changing:
final ObservableList<ObservableList<String>> data = null;
To:
final ObservableList<ObservableList<String>> data = FXCollections.observableArrayList();
Should solve your problem.

Foreign Key violation when inserting nested collections in EF6 (database first)

I have a nested collection in a database first project using Identifying Relationships
For example (showing the primary entity keys only):
+--Quotes--+ +------State-----+ +---State Info---+
|ID (int) | -(1-*)-> | Quote_ID (int) | -(1-*)-> | Quote_ID (int) |
+----------+ | State_ID (int) | | State_ID (int) |
+----------------+ | Info_ID (int) |
+----------------+
Note that in the first association, it is a one-to-many association where Quotes.ID --> Quote_ID.
The second association is a one-to-many composite key who's principal keys are Quote_ID/State_ID.
Now, let's say that Quote already exist (as theQuote) and I'm adding a new state:
theQuote.States.add(new State with {.State_ID=5})
And now I'm adding a new state info:
StateObj.StateInfos.add(New StateInfo with {.Info_ID=38})
Now I hook up a SQL profiler and save it:
db.SaveChanges()
What is happening is that I see two inserts:
exec sp_executesql N'INSERT [dbo].[States]([Quote_ID], [State_ID])
VALUES (#0, #1)',#0=153888,#1=5
exec sp_executesql N'INSERT [dbo].[StateInfo]([Quote_ID],[State_ID],[Info_ID])
values (#0, #1, #2)',#0=0,#1=0,#2=38
Note that in the first insert, the child collection, EF understands the relationship and automatically inserts the correct quote_id. However, in the second insert, the grandchild collection, it doesn't properly synch up the association and does not know the proper values. This results in an unfortunate "the Insert statement conflicted with the FOREIGN KEY constraint ..." SQL error.
Now this scenario works just fine if the StateObj already exists and I'm only inserting StateInfo. I need to be able to insert both State and StateInfo.
Seems like a reasonable request of EF6, but for some reason, I cannot get this to work. I've tried changing the StoreGeneratedPattern property of the entity keys to "Identity" but to no avail.
Any thoughts?
I have a reason why this is happening. Apparently, I have an overlapping key.
The table model I presented was not complete. I have an additional association that apparently creates the issue:
+--Quotes--+ +------State-----+ +---State Info---+
|ID (int) | -(1-*)-> | Quote_ID (int) | -(1-*)-> | Quote_ID (int) |
+----------+ | State_ID (int) | | State_ID (int) |
| StateView (nav)| | Info_ID (int) |
+----------------+ +----------------+
^
+-StateView-+ | (1-*)
| ID (int) |----+
+-----------+
The association is with StateView.ID as the primary and State.State_ID as the foreign key. If this relationship is removed, db.savechanges works as expected.
Alternatively, instead of using
theQuote.States.add(new State with {.State_ID=5})
Do this instead:
dim StateViewObj as StateView=db.StateView.Find(5)
theQuote.States.add(new State with {.StateView=StateViewObj})
This seems to work.

What data type is returned by this LocalStorage command?

There is an LocalStorage example in the Qt documentation
function findGreetings() {
var db = LocalStorage.openDatabaseSync("QQmlExampleDB", "1.0", "The Example QML SQL!", 1000000);
db.transaction(
function(tx) {
// Some other commands
// Show all added greetings
var rs = tx.executeSql('SELECT * FROM Greeting');
}
)
}
What's the data type of rs?
See the Quick Local Storage QML module documentation:
results = tx.executeSql(statement, values)
This method executes a SQL statement, binding the list of values to
SQL positional parameters ("?").
It returns a results object, with the following properties:
| Type | Property | Value | Applicability |
-----------------------------------------------------------------------------------------
| int | rows.length | The number of rows in the result | SELECT |
-----------------------------------------------------------------------------------------
| var | rows.item(i) | Function that returns row i of the result | SELECT |
-----------------------------------------------------------------------------------------
| int | rowsAffected | The number of rows affected by a modification | UPDATE,DELETE |
-----------------------------------------------------------------------------------------
| string | insertId | The id of the row inserted | INSERT |
results = tx.executeSql(statement, values)
This method executes a SQL statement, binding the list of values to SQL positional parameters ("?").
It returns a results object, with the following properties: link
If all you want is to know the type of returned object, just do:
var rs = tx.executeSql(...);
console.log(rs);
qml: [object Object]

Resources