Rowid after Insert in Room - android-room

I'm not sure about the value returned by an insert using the Room Persistence Library for Android, when the primary key is an autogenerated field.
Say you have a Room Entity like this:
#Entity()
public class Message {
#PrimaryKey(autoGenerate = true)
public long id;
public String text;
}
and a Dao interface like this:
#Dao
public interface MessageDao {
#Insert
long insert(Message messages);
#Update
void update(Message... messages);
}
I create a Message instance, and then I persist it like this:
Message message = new Message();
message.text = "Hello!"
long rowId = AppDatabase.getInstance(context).messageDao().insert(message);
Is the rowid value returned by the insert() always equal to the value assigned by Room to the primary key field "id", or they can differ?
In other words, is the "id" field an alias for the rowid column of the underlying SQLite table or not?
If they would be alias, I could store the rowid value in my "id" field, for future use (e.g. for update), this way:
message.id = rowId;
message.text = "Goodbye!"
AppDatabase.getInstance(context).messageDao().update(message);
If they are not alias, how can I do that?

As the documentation (unfortunately not in the #Insert documentation) say:
If the #Insert method receives only 1 parameter, it can return a long,
which is the new rowId for the inserted item. If the parameter is
an array or a collection, it should return long[] or List
instead.
To understand what rowId is follow this link: https://www.sqlite.org/rowidtable.html
The PRIMARY KEY of a rowid table (if there is one) is usually not the
true primary key for the table, in the sense that it is not the unique
key used by the underlying B-tree storage engine. The exception to
this rule is when the rowid table declares an INTEGER PRIMARY KEY. In
the exception, the INTEGER PRIMARY KEY becomes an alias for the rowid.
So... yes. rowId in your case IS an alias of your primary key. And YES you can store it for future use.

Related

spring data jpa + unwanted unique key generation

I am using spring data jpa for creation of my tables. My Requirement.
I have two Tables.
Basket Table - It has one to many Relationship with the Item table. A basket can have many Items.
Item Table - Here an Item can be associated with many Baskets.
I am using IGNORE_ROW_ON_DUPKEY_INDEX to make sure that the same combination of basketId and itemId, does not get persisted
So there is a mapping table in between in which holds the mapping of baskets and items. Now, in this table, i want the combination of basketId and itemId to be unique. Below is my entity stucture.
#Entity
Class Basket{
#Id
private long basketId;
...
#OneToMany(cascade = {CascadeType.Merge, CascadeType.DETACH, CascadeType.REFRESH})
#JoinTable(
name= "mapping_table",
joinColumns = #JoinColumn(name ='basketId'),
inverseJoinColumns = #JoinColumn(name ='itemId'),
indexes = {#Index(name = "my_index", columnList = "basketId, itemId", unique = true)}
#SQLInsert(sql = "INSERT /*+ IGNORE_ROW_ON_DUPKEY_INDEX (mapping_table, my_index) */ INTO mapping_table(basketId, itemId) values (?,?)")
private List<Item> itemList;
...
}
#Entity
Class Item{
#Id
private long itemId;
}
my_index with the combination of both the keys are getting created, as expected in the mapping_table
Problem 1:
In the mapping_table, for some wierd reason, a new unique constraint with only itemId is created. Due to this unique key constraint, i am not able to persist rows where an item is associated with multiple baskets. As i said, i want the combination of both the keys to be unique and i am achieving this by creating the index (my_index)
Problem 2:
Why is basketId (which is also Identifier) in the basketTable not marked as unique in the mapping table. This not a problem but more of a question. Becuase itemId which is identifier in the item table has unique key constraint in the mapping table.
Solution :
I create the tables using spring data jpa, login to the db manually and drop the unique key constraint and the persist. But this is not possible in Production
Question
I want to do alter table to drop the constraint first before the persist thing happens. How to do that.
P.S, As you can see, I have imagined these tables and have not put the names of the actual table. Not withstanding the made up table names, the problem statement is accurate. I am using Oracle as target DB
Try to use a Set instead of a List, JPA should generated the correct schema with the correct constraints.

Insert default entity from enum

I want to insert a default value to the status column in my table when a new record gets created. Here is my Entity class column definition.
Cost.java
#Column(nullable=false)
private FinanceStatusEnum status = FinanceStatusEnum.Inputter;
And this is my DTO definition.
CostDTO.java
#JsonProperty("status")
private FinanceStatusEnum status;
I'm still getting Column 'status' cannot be null error while performing the insert. What's going wrong?
Did you ever try to debug your code to see what is going on? I bet that your DTO just has a null status and you are blindly copying the value over to your entity which then obviously blows up due to your not-null constraint. Just set the default value on the entity in case the value is null before persisting the object.

Avoid duplicate primary keys after database intialization in spring-boot 2

The default #GeneratedValue strategy used to work in a spring boot 1.5 web app, without duplicate id conflicts of any type
... using a simple entity such as this one
// in my/package/Car.java
// ...
#Entity
public class Car {
private long id;
private String company;
private String model;
#Id
#GeneratedValue
public long getId() {
return id;
}
// ... more getters and setters
}
... and initializing the DB at start-up with
# in src/main/resources/import.sql
insert into car values (1, 'Tesla', 'Roadster');
... and later inserting another car with
Car c = new Car();
c.setCompany("Ford");
c.setModel("Pinto");
entityManager.persist(c);
entityManager.flush();
// expect no issue inserting, and a valid ID
log.info("Assigned ID is " + c.getId());
... used to result in a new Car with id 2. I do not really care about the generated ID, as long as there is no conflict. However, this same code now throws the following exception:
org.hsqldb.HsqlException: integrity constraint violation: unique constraint or index violation; SYS_PK_10095 table: CAR
(the DB is HSQL, and I would much rather not have to replace it)
... because the default sequence generation in hibernate 5.2 now does not take existing inserts into account.
What are my possible work-arounds to still allow the database to be initialized via import.sql? I know I can
use very large ids at initialization time (but this is just kicking the can down the road, and not a real solution: eventually the sequence will catch up and break things)
write my own sequence generator (but there has to be a much easier way of initializing a DB!)
use the old sequence generation (but again, why did they change it if there was no advantage to doing so? hibernate developers surely had some better way of initializing things in mind!).
somehow specify a starting value for new IDs (how do I do this in a fail-safe way? is there a property that can go into my application.properties to keep this centralized?)
I want to use this in the context of a spring-boot web app, and to keep it as simple and close to best practices as possible. Suggestions?
From version 5 SEQUENCE is used instead of IDENTITY for id generation. Migration from Hibernate 4 to 5
What happened?
You inserted record with ID 1 using script. Sequence remains at 1. It wants to insert 1 what is causing unique PK violation.
Solution
Don't use generation type auto. Use IDENTITY. Then inserting records by script, IDENTITY will be automatically increased. Also you don't need to insert ID value:
DECLARE temp_id INTEGER;
INSERT INTO CUSTOMERS VALUES (DEFAULT, firstname, lastname, CURRENT_TIMESTAMP);
SET temp_id = IDENTITY();
INSERT INTO ADDRESSES VALUES (DEFAULT, temp_id, address);

Golang gorm preloading

I'm writing my first app in golang, so sorry for newbie question, but I wasn't able to find the solution for the following problem:
I have two tables, position and attachment. Each position can have multiple attachments. Here is my model:
type Positions struct {
Sys_id int `gorm:"AUTO_INCREMENT" gorm:"column:sys_id" json:"sys_id,omitempty"`
Name string `gorm:"size:120" gorm:"column:name" json:"name,omitempty"`
OpenPositions int `gorm:"column:open_positions" json:"open_positions,omitempty"`
ContactList string `gorm:"size:1000" gorm:"column:contact_list" json:"contact_list,omitempty"`
Attachments []Attachment `gorm:"ForeignKey:RecordId"`
}
type Attachment struct {
Sys_id int `gorm:"AUTO_INCREMENT" gorm:"column:sys_id" json:"sys_id"`
Name string `gorm:"size:255" gorm:"column: name" json:"name"`
File string `gorm:"size:255" gorm:"column:file" json:"file"`
RecordId int `gorm:"column:record_id" json:"record_id"`
Table string `gorm:"size:255" gorm:"column:table" json:"table"`
// ...
}
I want to query the db and get positions with attachments
positions2 := []models.Positions{}
err := db.Where("open_positions > ?", 0).Preload("Attachments", "`table` = ?", "user_position").Find(&positions2)
if err != nil {
log.WithFields(log.Fields{
"type": "queryerr",
"msg": err,
}).Error("faked up query")
}
Result of this query - I get positions correctly but the attachments are empty.
(can't preload field Attachments for models.Positions)
level=error msg="faked up query" msg=&{0xc04200aca0 can't preload field Attachments for models.Positions 6 0xc042187e40 0xc042187d90 0xc0422cd4a0 0 {0xc042225130} false map[] map[] false}
Thanks in advance for help
Models in your example have custom primary column names.
So, when only ForeignKey set for "has_many" association, Gorm trying to find Position's column Attachment.RecordId refers to.
By default it uses Position as prefix and Id as column name for this. But neither RecordId column has prefix Position nor Position model has column Id, so it fails.
In such case for "has_many" association you should specify both Foreign Key and Association Foreign Key.
In your example Association Foreign Key is the Position.Sys_id column and Attachment.RecordId refers to it.
So it should be fixed just by adding Association foreign key:
Attachments []Attachment `gorm:"ForeignKey:RecordId;AssociationForeignKey:sys_id"`
Looks like it is not about Go or Gorm but about SQL.
W3SCHOOLS:
A FOREIGN KEY in one table points to a PRIMARY KEY in another table.
But RecordId is not a primary key in your model. Let the foreign key refer to a primary key. It should be fixed with:
RecordId int `gorm:"column:record_id" gorm:"primary_key" json:"record_id"`

Hibernate entity with enum foreign key

I'm not sure if the topic name makes sense.
Anyway, the problem is that in my table I have column which stores fk to dictionary table and I want to map it in hibernate in a way that getType will return a value from this dictionary. As an example I have row with type id = 1 which in dictionary corresponds to HIGH, and I have such enum declared in java as ProductType, I want to have method
ProductType getType() which will automatically map values from column type to my enum.
If something's not clear, please let me know.
Thanks in advance!
This is the answer to my question
#Column(name="TYPE_ID")
#Enumerated(EnumType.ORDINAL)
private MyType myType;
Of course my enum looks as follows:
public enum MyType {
HIGH(1),
LOW(2);

Resources