Spring Data JDBC save to two tables - spring

How to save an entity to two tables at the same time using Spring Data JDBC?
class MyEntity {
/* to be saved in table #1 */
int ID; /* auto-generated in table #1 */
String name;
/* to be saved in table #2 */
int titleID; /* auto-generated in table #2 */
String title;
}
I am new to Spring. It took me two days to find out how to do INNER JOIN query using Spring Data JDBC.

There is no special support in Spring Data JDBC for this.
You can do one of the following:
create an updatable view on the two tables, that joins the two tables and map your entity to that view. In order to be able to update both tables you might have to add triggers to the view, depending on the capabilities of your database.
You might split the entity into two with a 1:1 relationship with each being persisted in one table.

Related

SpringData JPA: Query with collection of entity as parameter

I have a list of entities on which I want to perform an update, I know I could update the table with list of String/Integer.. etc as the parameter with something like
#Query("update tableName i set i.isUpdated = true where i.id in :ids")
void markAsUpdated(#Param("ids") List<Integer> itemIds);
I'm trying to avoid repeated conversion of list of entities to list of Ids for making the query in DB. I know there are deleteAll and deleteInBatch commands which accept parameter as list of entities.
How do I do this in JPA Query, I tried the following but it didn't work yet.
#Modifying(flushAutomatically = true, clearAutomatically = true)
#Query("update tableName i set i.updated = true where i in :items")
void markAsUpdated(#Param("items") List<Item> items)
The query needs ids, it doesn't know how to deal with entities.
You have multiple options:
Just pass ids to the method, the client is responsible for extracting ids.
Pass entities and use SpEL for extracting ids
As suggested in the comments use a default method to offer both APIs and to delegate from one to the other.
As for the question that came up in the comments: You can move the method for extracting the id into a single method by either have relevant entities implement an interface similar to this one:
interface WithId {
Long getId();
}
Or by passing a lambda to the method, doing the conversion for a single entity:
List<ID> extractIds(List<E> entities, Function<E, ID> extractor) {
// ...
}

How can I delete all records from a table?

I've been searching for an answer on how to delete ALL records from a table using LINQ method syntax but all answers do it based on an attribute.
I want to delete every single record from the databse.
The table looks like so:
public class Inventory
{
public int InventoryId { get; set; }
public string InventoryName { get; set; }
}
I'm not looking to delete records based on a specific name or id.
I want to delete ALL recods.
LINQ method syntax isn't a must, bt I do prefer it since it's easier to read.
To delete all data from DB table I recommend to use SQL:
Trancate Table <tableName>
Linq is not meant to change the source. There are no LINQ methods to delete or update any element from your input.
The only method to change you input, is to select the (identifiers of the )data that you want to delete in some collection, and then delete the items one by one in a foreach. It might be that your interface with the source collection already has a DeleteRange, in that case you don't have to do the foreach.
Alas you didn't mention what your table was: Is it a System.Data.DataTable? Or maybe an Entity Framework DbSet<...>? Any other commonly used class that represents a Table?
If you table class is a System.Data.DataTable, or implements ICollection, it should have a method Clear.
If your tabls is an entity framework DbSet<...>, then it depends on your Provider (the database management system that you use) whether you can use `Clear'. Usually you need to do the following:
using (var dbContext = new MyDbContext(...))
{
List<...> itemsToDelete = dbContext.MyTable.Where(...).ToList();
dbContext.MyTable.RemoveRange(itemsToDelete);
dbContext.SaveChanges();
}

How to connect three tables using only one entity/class in Spring & Hibernate

I have only one entity which is School - a class (example). I have 7 fields in there and those fields are from 3 different tables. The first table for example is called Classroom, second is the Teachers, third is Subject. The teachers and subject table are connected by a pk: subject_id while the classroom table and teachers table are connected by classroom_id.
I tried secondary tables but it looks like it's not correct. How to connect those tables inside a single entity and write a query in the DAO IMPLementation
You should use Entity per Table.
If you need to select into non database related Model class, you can be done easily with spring-data-jpa.
After create the Model class (like School) just use the following sample to query:
class ProgrammerNameAndCity{
fields...
allArgConstructor...
}
public interface ProgrammerRepository extends JpaRepository<Programmer,Long> {
#Query(" select new com.zlrx.database.pojo.ProgrammerNameAndCity(p.name,p.address.city) " +
"from Programmer p where p.idNumber=?1")
ProgrammerNameAndCity findNameAndCityByIdNumber(String idNumber);
}
In this example the programmer has an address field (OneToOne), but you can create any kind of query, the important thing here is the constructor call of the model.
If you want to use plain sql or impl class instead of interface to query, you can use Spring's RowMapper too.
class ProgrammerNameAndCity{
fields...
allArgConstructor...
}
public interface ProgrammerRepository extends JpaRepository<Programmer,Long> {
#Query(" select new com.zlrx.database.pojo.ProgrammerNameAndCity(p.name,p.address.city) "
+ "from Programmer p where p.idNumber=?1")
ProgrammerNameAndCity findNameAndCityByIdNumber(String idNumber);
}

Spring mvc with hibernate #OneToMany relationship mapping

enter image description hereI have two table one is Credit and second is Debit. I want #OneToMany relationship. in credit table only single row of data and In debit table multiple row of data
Credit table:
cid
openingBalance
date
debittotal
drawertotal
debittotalplusdrawertotal
todaybusiness
all row of only single row data
Debit table:
did
amounnt
description
amount and description multiple data add
I am using Spring mvc with hibernate project structure is just like below
controller
entity
dao
daoImpl
service
serviceImpl
How to create enitiy with #OneToMany Relationship and when I save that data then all data will save at time into two table
You need Cascade persist for this.
#OneToMany(mappedBy="credit", cascade=CascadeType.PERSIST)
List<Debit> debits;
and then in your dao:
Credit credit = new Credit(......);
credit.setDebits(/*the list of debits*/)
entityManager.persist(credit);
or if you're using springdata jpa :
repository.save(credit);

Room Persistence Library - CREATE VIEW

I need to use a SQL VIEW in a query using Room Persistence Library.
Using Commonsware's answer here I've been able to run a raw SQL statement to create the view during DB creation.
Room.databaseBuilder(context, MyDatabase.class, DB_NAME)
.addCallback(new RoomDatabase.Callback() {
#Override
public void onCreate(#NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
db.execSQL("CREATE VIEW view_name " +
"AS SELECT [...] "
);
}
})
.build();
The VIEW is actually created on the SQLite DB and works fine, but I cannot refer to the it in my Dao's #Query because I get a compile-time error:
Error:(100, 48) error: There is a problem with the query: [SQLITE_ERROR] SQL error or missing database (no such table: view_name)
Any idea on how to let Room to know about my view or to ignore the error?
UPDATE 17/12/2018
Version 2.1.0 and higher of the Room persistence library now provides support for SQLite database views:
https://developer.android.com/training/data-storage/room/creating-views
(see D-D's comment)
UPDATE 15/12/2017
Be aware that this solution actually breaks DB migrations.
Problem is with the Entity primary key that obviously doesn't exist on the view, so migration is not valid.
See CommonsWare's comment for a possible hacky workaround.
ORIGINAL ANSWER
It seems that this is not possible at the moment using Room.
Anyway I've done it using a workaround: I've created an Entity with the same name and columns as the view (only the name is actually mandatory), this will create a table on DB and allow you to use that table name in queries without compile-time errors.
Then during Room DB creation I DROP this entity's table just before the CREATE VIEW.
Room
.databaseBuilder(context, DueDatabase.class, DB_NAME)
.addCallback(new RoomDatabase.Callback() {
#Override
public void onCreate(#NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
//Drop the fake table and create a view with the same name
db.execSQL("DROP TABLE view_name");
db.execSQL("CREATE VIEW view_name " +
"AS SELECT [...]"
);
}
})
.build();

Resources