I am using typeorm and postgress in nestjs.
I've created migration script to change Table Column from enum to enum[] and set old value as first element in the array:
export class MultiSpecialities implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "visits" ALTER COLUMN "segmentTag"
TYPE "public"."visits_segmenttag_enum"[] USING array[segmentTag]`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
//.....
}
}
the result is the column type changed but the previous data has corrupted, i.e it trimmed the value first & last letter.
,e.g:
suppose to be: gastroenterology , dental care
Related
Hi im trying to delete user by his id from a table in Postgres database.
Im using Spring and R2DBC and trying to use DatabaseClient.execute("sqlCommand") for my custom delete query:
import org.springframework.data.r2dbc.core.DatabaseClient;
#Service
#Transactional
public class CustomSqlService {
private final DatabaseClient databaseClient;
public Mono<Void> deleteWithCustomSql(String sql) {
databaseClient.execute(sql)
return Mono.empty();
}
Where sql is "DELETE FROM user_table WHERE user_id = 1;"
Method in the Controller:
#RestController
#RequestMapping("postgres/")
#Timed
public class PostgresController {
// omitted code
#DeleteMapping(path = "/delete_user/{userId}")
public Mono<Void> deleteUser(#PathVariable("userId") Long userId) {
return customSqlService.deleteWithCustomSql("DELETE FROM user_table WHERE user_id = " + userId);
}
But when I test it, command is not working. When i debug i can see there's MonoOnResumeError in the result from .execute().
I have other methods that perform insert and select statements in the same fashion and they work well.
The test I have for it:
#Test
void shouldDeleteDataFromTable() {
User user = User.builder()
.userId(1L)
.sessionId(2L)
.timestamp(10L)
.build();
webTestClient
.post()
.uri("/postgres/save_user")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.body(Mono.just(user), User.class)
.exchange()
.expectStatus().isOk()
webTestClient
.delete()
.uri("/postgres/delete_user/1")
.exchange()
.expectStatus()
.isOk();
userRepository.findAll().take(1).as(StepVerifier::create)
.expectNextCount(0)
.verifyComplete();
How to correctly use databaseClient.execute() for custom delete query in PostgreSQL ?
Hope you are using the latest R2dbc 1.0 and Spring Data R2dbc(managed by Spring Boot 3.0).
Your method deleteWithCustomSql does not work. There is no subscription on the databaseCLient.exectue, the sql is never be executed and return a result.
Try to change to the following, move sql here, and use bind to bind a parameter to sql.
public Mono<Long> deleteByUserId(Long userId) {
return databaseClient.sql("DELETE FROM user_table WHERE user_id = :userId")
.bind("userId", userId)
.fetch()
.rowsUpdated();
}
In the controller, changed to the following.
#DeleteMapping(path = "/users/{userId}")
public Mono<ResponseEntity> deleteUser(#PathVariable("userId") Long userId) {
return customSqlService.deleteByUserId(userId)
.map(deleted -> {
if(deleted>0) return noContent().build();
else return notFound().build();
});
}
Check my working example of delete operations, which demonstrates how to bind a parameter in sql, it is based on the latest Spring Data R2dbc/Postgres.
I have a little problem. But I dont know why it doesnt work. And I dont know how to post all ids by postman.
I am using unit of work with generic repository. I want to send int[] ids to my controller. I dont want to send entity. I searched a lot it today. And I changed my code. But what is problem now?
This is my repostiroy:
public async Task DeleteRangeAsync(Expression<Func<T, bool>> predicate)
{
IQueryable<T> query = _dbSet.Where(predicate);
await Task.Run(() => { _dbSet.RemoveRange(query.AsNoTracking()); });
}
This is my KulturManager:
public async Task<IResult> HardDeleteRangeAsync(int[] ids)
{
await UnitOfWork.Kulturs.DeleteRangeAsync(c => ids.Contains(c.Id));
await UnitOfWork.SaveAsync();
return new Result(ResultStatus.Success, Messages.Info("Kultur", "HardDelete"));
}
And this is my KulturController:
[HttpDelete("{ids}")]
public async Task<IActionResult> HardDeleteRangeAsync(int[] ids)
{
var result = await _kulturManager.HardDeleteRangeAsync(ids);
return Ok(result.Message);
}
Thank you for help
You shouldn't fetch all the entities you want to delete. Instead create stub entities for RemoveRange. If you don't have a common base class, this requires reflection, but with a common entity base class you can do it like this:
public void DeleteRange<T>(int[] ids) where T: BaseEntity, new()
{
_dbSet.RemoveRange(ids.Select(i => new T() { Id = i }).ToList());
}
or if the method is in a generic class, the method would look like
public void DeleteRange(int[] ids)
{
_dbSet.RemoveRange(ids.Select(i => new T() { Id = i }).ToList());
}
And there's no reason to mark this as Async now since it doesn't do any database access.
I have this database structure
orders ====► order_items ====► order_item_meta
║ |
║ |
▼ ▼
order_meta products
The relations are orders hasMany order_items which hasManyThrough order_item_meta, orders also hasMany order_meta.
In addition, the order_items/product_id needs to be joined with the products table.
I have the order_id and I am trying to get the whole data in one call. But I have a weird issue. This is the current code:
$orders = Orders::
with([
'order_items' => function($q) { //#1
$q->leftJoin('products','order_items.product_id', '=', 'products.id');
}
])
->with(['order_items.orderitem_meta']) //#2
->with(['order_meta']); //#3
It seems that with#1 and with#2 are interfering with each other.
Case1: If I do with#1+with#3, I am able to see in the result the data from the product table + the data from order_items, but not the data from order_item_meta.
Case2: If I do with#2+with#3, I am able to see in the result the data from the from order_items + data from order_item_meta, but not from the product table.
In both cases data from with#3 is ok.
But if I do all three together (with#1+with#2+with3) I get the same results as case1. data from order_item_meta is missing.
Orders.php
class Orders extends Model
{
public function order_items()
{
return $this->hasMany('App\OrderItem','order_id','id'); //'foreign_key', 'local_key'
}
public function order_meta()
{
return $this->hasMany('App\OrderMeta','order_id','id'); //'foreign_key', 'local_key'
}
public function orderitem_meta()
{
return $this->hasManyThrough(
'App\OrderItem',
'App\OrderItemMeta',
'order_item_id', // Foreign key on order_itemmeta table...
'order_id', // Foreign key on order_item table...
'id', // Local key on order_item table...
'id' // Local key on order_itemmeta table...
);
}
}
OrderItem.php
class OrderItem extends Model
{
public function order()
{
return $this->belongsTo('App\Orders');
}
public function orderitem_meta()
{
return $this->hasMany('App\OrderItemMeta','order_item_id','id'); //'foreign_key', 'local_key'
}
}
OrderItemMeta.php
class OrderItemMeta extends Model
{
protected $table = 'order_itemmeta';
public function orderitem()
{
return $this->belongsTo('App\OrderItem');
}
}
What is the correct way to do this query?
I solved it by adding a relationship between the order_items and the products:
in OrderItem.php
public function product()
{
return $this->hasOne('App\Products','id','product_id'); //'foreign_key', 'local_key'
}
then the query becomes this:
$orders = Orders::
with(['order_items.orderitem_meta','order_items.product','order_meta']);
and it works
I'm trying to complete a general repository for all of the entities in my application. I Have a BaseEntity with property Id, CreatorId and LastModifiedUserId. Now I'd like to Update a record in a collection, without having to modify the field CreatorId, so I have (from the client) an Entity valorized with some fields updated that I want to update.
Hi have 2 ways:
UpdateOneAsync
ReplaceOneAsync
The repo is created like this:
public class BaseRepository<T> : IRepository<T> where T : BaseEntity
{
public async Task<T> Replace/Update(T entity){...}
}
So it's very hard to use Update(1), since I should retrieve with reflection all the fields of T and exclude the ones that I don't want to update.
With Replace(2) I cannot find a way to specify which fields i should exclude when replacing an object with another. Projectionproperty in FindOneAndReplaceOptions<T>() just excludes the fields on the document that is returned after the update.
Am I missing a way in the replace method to exclude the fields or should I try to retrieve the fields with reflection and use a Update?
I don't know if this solution is ok for you .. what i do is :
Declare in Base Repo a method like
public virtual bool Update(TEntity entity, string key)
{
var result = _collection.ReplaceOne(x => x.Id.Equals(key), entity, new UpdateOptions
{
IsUpsert = false
});
return result.IsAcknowledged;
}
then in your controller when you want to update your entities is there where you set the prop you want to change .. like:
[HttpPut]
[ProducesResponseType(typeof(OrderDTO), 200)]
[ProducesResponseType(400)]
public async Task<ActionResult<bool>> Put([FromBody] OrderDTO value)
{
try
{
if (!ModelState.IsValid) return BadRequest(ModelState);
var orderOnDb = await _orderService.FindAsync(xx => xx.Id == value.Id);
if (orderOnDb == null) return BadRequest(Constants.Error.NOT_FOUND_ON_MONGO);
// SET PROPERTY TO UPDATE (MANUALLY)
orderOnDb.LastUpdateDate = DateTime.Now;
orderOnDb.PaymentMethod = value.PaymentMethod;
orderOnDb.StateHistory = value.StateHistory;
//Save on db
var res = await _orderRepo.UpdateAsync(orderOnDb, orderOnDb.Id);
return res;
}
catch (Exception ex)
{
_logger.LogCritical(ex, ex.Message);
throw ex;
}
}
Hope it helps you!!!
Given a PostgreSQL (9.5) stored procedure (with Npgsql driver) as:
CREATE OR REPLACE FUNCTION "GetAllDx"(
patient_recid integer,
tencounter timestamp without time zone) RETURNS SETOF view_dx
How is this executed from PetaPoco ? Can it be done? (I've been using Dapper).
Any help is much appreciated.
Very simple,
[TestMethod]
public void GetAllPatientsWithServices()
{
// Create a PetaPoco database object
var db = new chaosDB("localconnection");
// Calling stored procedure getallpatientswithservices()
var a = db.Fetch<view_patient>("Select * from getallpatientswithservices()");
foreach( var b in a)
{
Console.WriteLine("{0} - {1}", b.cpatient, b.chart_number);
}
}
Or, with a mixed-case procedure name:
[TestMethod]
public void GetDxLibrary()
{
// Create a PetaPoco database object
var db = new chaosDB("localconnection");
// Calling stored procedure with mixed case name
var a = db.Fetch<icd9>("Select * from \"GetDxLibrary\"()");
foreach (var b in a)
{
Console.WriteLine("{0} - {1}", b.code,b.cdesc);
}
}