Can Spring R2DBC execute batch insert and update at the same time? - spring

Can Spring R2BC save and update a batch at the same time?
I get a list of users (1 million rows from a file for example). Some of these users are new and I need to INSERT them to the table, and some need to be UPDATED due to changed data. It is not clear from the file which are new and which are not.
I'm considering user_id as the primary key
How can I describe this logic in code using Spring R2DBC?

It a little depend how much work you would like to do :)
Select then insert/update
The first way is quite simple to understand, but suboptimal in case of number of queries/database interactions.
#Transactional
Mono<User> save(User user){
return repository.findById(user.getId())
.flatMap(found -> repository.save(found.copyMutableValuesFrom(user)))
.switchIfEmpty(repository.save(user));
}
In first step you try to find user by id, then update (with fields rewrite in copyMutableValuesFrom) or insert.
Upsert
Second way is to use custom query:
interface UserRepository extends ReactiveCrudRepository<User, Long> {
#Modifying
#Query("""
INSERT INTO user (id, firstname, lastname) VALUES(1, :firstname, :lastname)
ON DUPLICATE KEY
UPDATE firstname=:firstname, lastname=:lastname
""")
Mono<Integer> maybeInsertMaybeUpdate(Long id, String firstname, String lastname);
}
This way limit number of queries, but strongly depends on database. Above query is for mySQL, but postgres version looks like:
INSERT INTO user (id, firstname, lastname) VALUES(1, :firstname, :lastname)
ON CONFLICT(id)
DO
UPDATE SET firstname=:firstname, lastname=:lastname
Batch
As in comment. You need to use construction like this:
Flux<Long> insertProductColors(List<User> users){
if (users.isEmpty()) return Flux.empty();
return databaseClient.inConnectionMany { connection ->
val statement = connection.createStatement(insertOrUpdateUserQuery)
users.forEach(user ->
statement.bind(0, user.id).bind(1, user.firstName, user.lastname).add()
);
return statement.execute().toFlux().flatMap( result ->
result.map ( row, meta -> row.get("id", Long.class) )
)
}
}
I'm not sure everything here, because I get some of my code in kotlin and translated it here, but general idea is probably clear.

Related

Partial update without retrieving the object from db

I am looking for some way to partially update an object without retrieving the object from DB.
Say I have an Employee entity containing the following properties -
firstName
lastName
phone
age
salary
The JSON I get in the update request may not contain all the properties. I need to make sure I update only the properties provided in the request and leave all other data unchanged.
I explored some ways of achieving partial update but all of them involves retrieving the data from db. I don't have this option since the db in my case is too slow and this will increase the response time. Please suggest
You can combine #Modifying and #Query annotation to issue an update query
#Modifying
#Query("update Employee e set e.firstName = :firstName, e.lastName = :lastName where e.id = :id")
void updateEmployeePartially(Long id, String firstName, String lastName);
For more information, you can check this article

how to select a user id and merge the updated user inputs in respective fields

i have a controller with #SessionAttributes("user_email") now i wish to do a merge operation for this particular user_email in session
i have a dao implementation class which performs merge operation as follows:
#Override
public boolean mergeusers(Users users) {
session.getCurrentSession().merge(users); //saves or updates the lawyer details //
return true;
}
but even though i give session.getcurrentSession it merges the new user input as a new user in the database instead of merging/updating the fiel that matches the session's user_email
im new to this could someone please tell me what im doing wrong
two options
populate the Id of the user before merging or
find the user from the database (findById) and update the data and merge it

Hibernate find object from database by few params

Can't find right query with few params.
Here is my query from DAO class:
public Notebook findByName(String name, Integer UserId) {
return (Notebook) sessionFactory.getCurrentSession().createQuery("from Notebook where ....");
}
I would like to get by this query object of Notebook by few params: name and user id(foreign key).
And i would like to get only one object, not list of objects even he has only 1 element.
The method createQuery(queryString) returns a Query on which you can set the parameters e.g.
Query query = createQuery("from Notebook where id=:id and title=:title");
query.setParameter("id", id);
query.setParameter("title", title);
query.setMaxResults(1);
query.uniqueResult(); // fetch the object.
If the query returns more then one results be sure to set setMaxResults() or an exception will be thrown.
First
Edit to
public Notebook findByName(String name, Integer UserId) {
return (Notebook) ....createQuery("from Notebook where ....")...uniqueResult;
}
BTW: I am not including the part where you are setting the parameters for your query
If there is no a unique result, uniqueResult throws an exception.
Be sure your query statement is very specific and you are including something like master.pk=child.fk (where pk should fk)
could you update and include the complete query statement?

A BaseClass extends from Eloquent to handle complicated search condition in laravel

Previous description of my problem is wrong. So I delete it and write a new one.
There are several tables, following are their structures
Table1: id, name
Table2: id, name, date1, date2
Table3: id, name, desc
maybe more tables...
And some html pages, each one references to a table. Every page has one or more search box to search data in related table. I use Ajax to handle the search work. I take some examples as below
Page related table search columns http params
Page1: Table1 id, name q={"id": 1, "name":"bill"}
Page2: Table2 id, date1, date2 q={"id": 1, "date1":"2014-7-19", "date2":"2014-7-20"}
Page3: Table3 id, name q={"id": 1, "name":"bill", "desc":"boss"}
Then I want to create a BaseModel extends from Eloquent, then all other specific Models extends from BaseModel.
I hope there will be a "search" method it can handle all of complicated search actions in BaseModel.
It's hard to suggest a good solution since you don't really tell us, what needs to be done.
This is the most straightforward solution for you, using query scopes:
// BaseModel extending Eloquent Model
public function scopeSearch($query, $jsonSearch)
{
$wheres = $this->parseSearch($jsonSearch);
$query->where($wheres); // WHERE X = Y AND Z = A ...
}
protected function parseSearch($jsonSearch)
{
// validate your input here, make sure it's correct according to your needs
}
Then:
// single result
AnyModel::search($yourJson)->first();
// collection
AnyModel::search($yourJson)->get();
// you can chain more methods if you like
AnyModel::search($yourJson)->where('x', 'y')->orderBy('x')->get();

Joining asp_Users db tables in LINQ using asp.net MVC

I am working on an example asp.net project using MVC, but my database is a live one which I can't make changes to (technically it's the test version of this database but my point is changes to the database aren't possible).
I use the UserID from the asp_Users table to store who makes changes to various aspects of the system, and I want to start showing the user name in various front-end tables, but how do I link the tables to get this user name?
So to clarify, I'm going to want to do this for several tables throughout the system so I was hoping I could do it using LINQ.
I can get the info I want from using the join query, but how do I pass this to my View to use?
var plans = from users in db.aspnet_Users
join import in db.Plan_Imports
on users.UserId.ToString()
equals import.User_ID
select new
{
Date = import.Date,
UserName = users.UserName
};
Sample tables
asp_Users
UserID
UserName
...
table1
ID
field1
field2
...
User_ID <--- ref to asp_Users
table2
ID
field1
field2
...
User_ID <--- ref to asp_Users
I would create a ViewModel for each view.
ViewModel is just a POCO class
public class PlanViewModel
{
public string UserName { set;get;}
public DateTime ImportDate { set;get;}
}
Then Get the Data to this ViewModel/Collection of ViewModel using LINQ Projections from your query.
public ActionResutl Show()
{
var plans = (from users in db.aspnet_Users
join import in db.Plan_Imports
on users.UserId.ToString()
equals import.User_ID
select new PlanViewModel
{
ImportDate = import.Date,
UserName = users.UserName
}).ToList();
return View(plans);
}
Now Lets make our view strongly typed to a collection of our PlanViewModel
#model List<PlanViewModel>
#foreach(var plan in Model)
{
<p>#plan.UserName</p>
<p>#plan.ImportDate.ToString()</p>
}
The solution provided by Shyju worked perfectly, and it wasn't too complex to do, however I decided that I didn't think using LINQ was appropriate in this case as the code was getting out of hand for what should be a simple call.
What I did instead was use a stored procedure to get the information, and saved it to a complex object which I passed to my view.
The code is now much neater and easier to manage, as the code above became just
var plans = db.SP_SelectImports();
Read more about stored procedure mapping here: http://dotnet.dzone.com/news/mapping-stored-procedure

Resources