How to tranverse through the SOAP response in eSQL - soap

I am new to ESQL programming language, I need bit a small help in writing it.
I have a requirement in IIB where in I receive SOAP response from SOAP Request node and send the transformed message to MQ queue.
Below is the sample input
<Response xmlns="http://www.xyz.fr/Retail/1.0">
<Result xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Output>
<Element>
<Notification>{ "employee": { "name": "sonoo", "salary": 56000, "married": true } } </Notification>
<collegeID>345</collegeID>
</Element>
<Element>
<Notification> { "employee": { "name": "sonoo", "salary": 56000, "married": true } }</Notification>
<collegeID>123</collegeID>
</Element>
</Output>
</Result>
</Response>
Below is the code which I have written
CREATE COMPUTE MODULE Compute1
CREATE FUNCTION Main() RETURNS BOOLEAN
BEGIN
-- CALL CopyMessageHeaders();
-- CALL CopyEntireMessage();
DECLARE myref REFERENCE TO InputRoot.XMLNSC.Response.Result.Output;
DECLARE Count INT CARDINALITY(myref.Element[]);
DECLARE i INT 1;
WHILE (i<=Count)DO
SET OutputRoot.JSON.Data = FIELDVALUE(myref.Element[i].Notification);
SET i = i + 1;
PROPAGATE TO TERMINAL 'out' DELETE NONE;
END WHIlE;
RETURN TRUE;
END;
CREATE PROCEDURE CopyMessageHeaders() BEGIN
DECLARE I INTEGER 1;
DECLARE J INTEGER;
SET J = CARDINALITY(InputRoot.*[]);
WHILE I < J DO
SET OutputRoot.*[I] = InputRoot.*[I];
SET I = I + 1;
END WHILE;
END;
CREATE PROCEDURE CopyEntireMessage() BEGIN
SET OutputRoot = InputRoot;
PROPAGATE TO TERMINAL 'out1' DELETE NONE;
END;
END MODULE;
In 'Count' variable I am not able to see the value, it is always showing '0'.
Count =0 but it should be 2 as per the input message.
In the input from 'Notification' field, I need to send JSON message to MQ queue using MQ Output node.
Could you please suggest is it because of namespace tagged with 'Response' field tag which I am not able to retrieve the count?

Related

Postgresql 11 Create or Replace Procedure GetMultipleResultSets(INOUT ref1 refcursor, INOUT ref2 refcursor); Automatic cursor deferencing using Npgsql

Requirement:
How to get back the multiple refcursor data from a postgresql 11 procedure (not a function) without using the fetch statement using npgsql 4.0 from ado.net.
Here is the sample which i have tried:
Postgresql Procedure:
CREATE OR REPLACE PROCEDURE public.GetMultipleResultSets(
INOUT ref1 refcursor,
INOUT ref2 refcursor)
LANGUAGE 'plpgsql'
AS $BODY$
begin
open ref1 for
select * from public."tblTestTable1";
open ref2 for
select * from public."tblTestTable2";
end;
$BODY$;
C# Code using Npgsql 4.0:
public DataSet ReturnAsDataSet(string procedureName)
{
this.dataSet = new DataSet();
OpenConnection();
NpgsqlTransaction objTransaction = this.Connection.BeginTransaction();
NpgsqlDataAdapter adapter = new NpgsqlDataAdapter();
NpgsqlCommand command = this.Connection.CreateCommand();
try
{
NpgsqlParameter refCursorParam1 = new NpgsqlParameter("#ref1", NpgsqlTypes.NpgsqlDbType.Refcursor);
refCursorParam1.Direction = ParameterDirection.InputOutput;
refCursorParam1.Value = "ref1";
command.Parameters.Add(refCursorParam1);
refCursorParam2 = new NpgsqlParameter("#ref2", NpgsqlTypes.NpgsqlDbType.Refcursor);
refCursorParam2.Direction = ParameterDirection.InputOutput;
refCursorParam2.Value = "ref2";
command.Parameters.Add(refCursorParam2);
command.CommandText = "call " + procedureName + "(#ref1, #ref2)";
command.Transaction = objTransaction;
adapter.SelectCommand = command;
adapter.Fill(dataSet);
objTransaction.Commit();
}
catch (NpgsqlException ex)
{
if (objTransaction != null)
objTransaction.Rollback();
throw new Exception(ex.Message);
}
finally
{
CloseConnection();
command.Dispose();
objTransaction.Dispose();
}
return this.dataSet;
}
This code will return a table having the "ref1", "ref2" as the columns and "ref1" and "ref2" as the values inside it as follows:
enter image description here
But I need the actual result sets returned from the procedure.
How can I achieve it without manually fetching those refcursor data.
I mean without using "fetch all ref" statement how can we retrieve the data by executing either ExecuteReader() or adapter.Fill() methods as above.
Is there any automatic cursor dereferencing available in npgsql?
Please provide the answer if anyone knows.
Thanks for your help in advance.
This is currently not done for you by Npgsql, this issue tracks it. You can see this long discussions on the pros and cons of this. At the moment you'll have to call FETCH on the cursors yourself.

Database operation expected to affect 1 row(s) but actually affected 0 row(s) with entity framework

I have the following table:
And I have the following trigger:
CREATE TRIGGER check_insertion_to_pushes_table
BEFORE INSERT
ON "Pushes"
FOR EACH ROW
EXECUTE PROCEDURE trg_insert_failed_push();
CREATE or replace FUNCTION trg_insert_failed_push()
RETURNS trigger AS
$func$
BEGIN
IF (NEW."Sent" = false) THEN
IF EXISTS(
SELECT *
FROM "Pushes"
where "Sent" = false
and "CustomerId" = NEW."CustomerId"
and "PushTemplateId" = NEW."PushTemplateId"
)
THEN
RETURN NULL;
END IF;
RETURN NEW;
ELSE
RETURN NEW;
end if;
END
$func$ LANGUAGE plpgsql;
If there is row in the DB where CustomerId and PushTemplateId and Sent are equal to new row and Sent is false I would like to pass insertion.
And I have the following test to check how it works:
public class Tests
{
private IPushRepository _pushRepository;
[NUnit.Framework.SetUp]
public void Setup()
{
var confBuilder = new ConfigurationBuilder();
var configuration = confBuilder.AddJsonFile("/home/aleksej/projects/makeapppushernet/TestProject/appsettings.LocalToProdDb.json").Build();
_pushRepository = new PushRepository(new ApplicationDbContext(configuration));
}
[Test]
public async Task Test1()
{
var push = new Push
{
CustomerId = 69164,
Sent = false,
PackageId = "com.kek.lol",
Category = "betting",
Advertiser = "Advertiser",
TemplateType = "opened_and_not_registration",
IntervalType = "minutes",
BottomDateTimeBorder = 90,
TopDateTimeBorder = 60,
ClientStartDateTime = DateTime.Now,
FCMResponse = "hello",
CreatedAt = DateTime.Now,
LangCode = "En",
PushBody = "Hello",
PushTitle = "Hello",
PushTemplateId = 15
};
var pushesList = new List<Push>
{
push
};
await _pushRepository.SaveAsync(pushesList);
Assert.Pass();
}
}
If I set false for Sent in the test I have the following exception:
Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
If I set true I have nothing. It just passes insertion.
Update
Ok, with the help of Shay Rojansky's answer I have the following trigger code:
CREATE TRIGGER check_insertion_to_failed_pushes_table
BEFORE INSERT
ON "FailedPushes"
FOR EACH ROW
EXECUTE PROCEDURE trg_insert_failed_push();
CREATE or replace FUNCTION trg_insert_failed_push()
RETURNS trigger AS
$func$
DECLARE
push "FailedPushes"%ROWTYPE;
old_push_id numeric;
BEGIN
old_push_id = (SELECT "FailedPushId"
FROM "FailedPushes"
where "CustomerId" = NEW."CustomerId"
and "PushTemplateId" = NEW."PushTemplateId");
push := new;
IF (old_push_id != 0)
THEN
push."FailedPushId" = old_push_id;
DELETE
FROM "FailedPushes"
where "CustomerId" = NEW."CustomerId"
and "PushTemplateId" = NEW."PushTemplateId";
return push;
END IF;
push."FailedPushId" = (SELECT count(*) FROM "FailedPushes")::numeric + 1;
return push;
END
$func$ LANGUAGE plpgsql;
Maybe not very elegant but it works.
You are in effect configuring PostgreSQL to ignore the INSERT under certain conditions, but EF Core isn't aware of this in any way. When you tell EF Core to add a new row, it expects for that to actually happen in the database. If the entity has any database-generated columns (identity, serial), EF Core also expects to receive the their values for the newly-inserted row (and will populate them back into the entity's CLR instance).
So AFAIK you can't just tell the database to ignore the INSERT and expect everything to work...
See this issue on EF Core upsert support which is somewhat related.
Maybe your model parsing to Action in the controller might not have accurate values.

How to execute 7zip without blocking the Inno Setup UI?

My Inno Setup GUI is frozen during unzip operations.
I've a procedure DoUnzip(source: String; targetdir: String) with the core
unzipTool := ExpandConstant('{tmp}\7za.exe');
Exec(unzipTool, ' x "' + source + '" -o"' + targetdir + '" -y',
'', SW_HIDE, ewWaitUntilTerminated, ReturnCode);
This procedure is called multiple times and the Exec operation blocks the user interface. There is only a very short moment between the executions, where the Inno GUI is dragable/moveable.
I know that there are other options for TExecWait instead of ewWaitUntilTerminated, like ewNoWait and ewWaitUntilIdle, but unfortunately they are not helpful in this case. Using ewNoWait would result in the execution of multiple unzip operations at the same time.
I'm looking for a way to execute an external unzip operation and wait for it to finish, but without blocking the user interface. How can i implement that?
Here are my notes and ideas:
Waiting for a process to finish, is blocking, unless you'll be waiting in a thread different from the main one. I think some kind of callback is needed, which is executed, when the unzip operation finishes.
I'm aware that Inno Setup doesn't provide this feature out of the box, see https://github.com/jrsoftware/issrc/issues/149
While searching for related issues on Stack Overflow, I came up with the question Using callback to display filenames from external decompression dll in Inno Setup, where I found Mirals's answer. It's using InnoCallback combined with another DLL.
I think, in my case this could be 7zxa.dll for the unzip operation. But it doesn't accept a callback. So, the following code is just a concept / idea draft. One problem is, that 7zxa.dll doesn't accept a callback.
Another problem is that the 7zxa API is not really inviting to work with.
[Code]
type
TMyCallback = procedure(Filename: PChar);
{ wrapper to tell callback function to InnoCallback }
function WrapMyCallback(Callback: TMyCallback; ParamCount: Integer): LongWord;
external 'WrapCallback#files:innocallback.dll stdcall';
{ the call to the unzip dll }
{ P!: the 7zxa.dll doesn't accept a callback }
procedure DoUnzipDll(Blah: Integer; Foo: String; ...; Callback: LongWord);
external 'DoUnzipDll#files:7zxa.dll stdcall';
{ the actual callback action }
procedure MyCallback(Filename: PChar);
begin
{ refresh the GUI }
end;
{ ----- }
var Callback : LongWord;
{ tell innocallback the callback procedure as 1 parameter }
Callback := WrapMyCallback(#MyCallback, 1);
{ pass the wrapped callback to the unzip DLL }
DoUnzipDll(source, target, ..., Callback);
procedure DoUnzip(src, target : String);
begin
DoUnzipDll(ExpandConstant(src), ExpandConstant(target));
end;
Update: #Rik suggested to combine the WinAPI function ShellExecuteEx() with INFINITE WaitForSingleObject.
I've implemented and tested this approach. The code is below.
The unzipping works, but the Inno Setup window is only moveable/dragable for a short moment between the individual unzip operations. During a long running unzip the GUI is fully unresponsive - no dragging/no cancel button.
I've added BringToFrontAndRestore(), but it seems the new process has the focus.
const
WAIT_OBJECT_0 = $0;
WAIT_TIMEOUT = $00000102;
SEE_MASK_NOCLOSEPROCESS = $00000040;
INFINITE = $FFFFFFFF; { Infinite timeout }
type
TShellExecuteInfo = record
cbSize: DWORD;
fMask: Cardinal;
Wnd: HWND;
lpVerb: string;
lpFile: string;
lpParameters: string;
lpDirectory: string;
nShow: Integer;
hInstApp: THandle;
lpIDList: DWORD;
lpClass: string;
hkeyClass: THandle;
dwHotKey: DWORD;
hMonitor: THandle;
hProcess: THandle;
end;
function ShellExecuteEx(var lpExecInfo: TShellExecuteInfo): BOOL;
external 'ShellExecuteEx{#AW}#shell32.dll stdcall';
function WaitForSingleObject(hHandle: THandle; dwMilliseconds: DWORD): DWORD;
external 'WaitForSingleObject#kernel32.dll stdcall';
function CloseHandle(hObject: THandle): BOOL; external 'CloseHandle#kernel32.dll stdcall';
procedure DoUnzip(source: String; targetdir: String);
var
unzipTool, unzipParams : String; { path to unzip util }
ReturnCode : Integer; { errorcode }
ExecInfo: TShellExecuteInfo;
begin
{ source might contain {tmp} or {app} constant, so expand/resolve it to path name }
source := ExpandConstant(source);
unzipTool := ExpandConstant('{tmp}\7za.exe');
unzipParams := ' x "' + source + '" -o"' + targetdir + '" -y';
ExecInfo.cbSize := SizeOf(ExecInfo);
ExecInfo.fMask := SEE_MASK_NOCLOSEPROCESS;
ExecInfo.Wnd := 0;
ExecInfo.lpFile := unzipTool;
ExecInfo.lpParameters := unzipParams;
ExecInfo.nShow := SW_HIDE;
if not FileExists(unzipTool)
then MsgBox('UnzipTool not found: ' + unzipTool, mbError, MB_OK)
else if not FileExists(source)
then MsgBox('File was not found while trying to unzip: ' + source, mbError, MB_OK)
else begin
{ ShellExecuteEx combined with INFINITE WaitForSingleObject }
if ShellExecuteEx(ExecInfo) then
begin
while WaitForSingleObject(ExecInfo.hProcess, INFINITE) <> WAIT_OBJECT_0
do begin
InstallPage.Surface.Update;
{ BringToFrontAndRestore; }
WizardForm.Refresh();
end;
CloseHandle(ExecInfo.hProcess);
end;
end;
end;
Like I suspected using INFINITE with WaitForSingleObject still blocks the main-thread. Next I thought using a smaller timeout with WaitForSingleObject. But the problem is still that the main-thread stays in the while loop of WaitForSingleObject and doesn't respond to moving. WizardForm.Refresh does not make it movable. It just refreshes the form but doesn't process other messages (like WM_MOVE). You need something like Application.ProcessMessages to allow the windows to move. Since Inno Setup doesn't have a ProcessMessages we could create one ourselves.
Below is your code with a ProcessMessage implemented. It does a 100 millisecond wait for WaitForSingleObject and if it's still in the wait-state it executes the ProcessMessage and Refresh. This will allow you to move the window. You can play a little with the value 100.
Another way could be that you save the ExecInfo and go on with some other install-part. In the final page you could check if the process is finished. If it's not loop with the AppProcessMessage until it is.
[Code]
#ifdef UNICODE
#define AW "W"
#else
#define AW "A"
#endif
const
WAIT_OBJECT_0 = $0;
WAIT_TIMEOUT = $00000102;
SEE_MASK_NOCLOSEPROCESS = $00000040;
INFINITE = $FFFFFFFF; { Infinite timeout }
type
TShellExecuteInfo = record
cbSize: DWORD;
fMask: Cardinal;
Wnd: HWND;
lpVerb: string;
lpFile: string;
lpParameters: string;
lpDirectory: string;
nShow: Integer;
hInstApp: THandle;
lpIDList: DWORD;
lpClass: string;
hkeyClass: THandle;
dwHotKey: DWORD;
hMonitor: THandle;
hProcess: THandle;
end;
function ShellExecuteEx(var lpExecInfo: TShellExecuteInfo): BOOL;
external 'ShellExecuteEx{#AW}#shell32.dll stdcall';
function WaitForSingleObject(hHandle: THandle; dwMilliseconds: DWORD): DWORD;
external 'WaitForSingleObject#kernel32.dll stdcall';
function CloseHandle(hObject: THandle): BOOL; external 'CloseHandle#kernel32.dll stdcall';
{ ----------------------- }
{ "Generic" code, some old "Application.ProcessMessages"-ish procedure }
{ ----------------------- }
type
TMsg = record
hwnd: HWND;
message: UINT;
wParam: Longint;
lParam: Longint;
time: DWORD;
pt: TPoint;
end;
const
PM_REMOVE = 1;
function PeekMessage(var lpMsg: TMsg; hWnd: HWND; wMsgFilterMin, wMsgFilterMax, wRemoveMsg: UINT): BOOL; external 'PeekMessageA#user32.dll stdcall';
function TranslateMessage(const lpMsg: TMsg): BOOL; external 'TranslateMessage#user32.dll stdcall';
function DispatchMessage(const lpMsg: TMsg): Longint; external 'DispatchMessageA#user32.dll stdcall';
procedure AppProcessMessage;
var
Msg: TMsg;
begin
while PeekMessage(Msg, WizardForm.Handle, 0, 0, PM_REMOVE) do begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
end;
{ ----------------------- }
{ ----------------------- }
procedure DoUnzip(source: String; targetdir: String);
var
unzipTool, unzipParams : String; // path to unzip util
ReturnCode : Integer; // errorcode
ExecInfo: TShellExecuteInfo;
begin
{ source might contain {tmp} or {app} constant, so expand/resolve it to path name }
source := ExpandConstant(source);
unzipTool := ExpandConstant('{tmp}\7za.exe');
unzipParams := ' x "' + source + '" -o"' + targetdir + '" -y';
ExecInfo.cbSize := SizeOf(ExecInfo);
ExecInfo.fMask := SEE_MASK_NOCLOSEPROCESS;
ExecInfo.Wnd := 0;
ExecInfo.lpFile := unzipTool;
ExecInfo.lpParameters := unzipParams;
ExecInfo.nShow := SW_HIDE;
if not FileExists(unzipTool)
then MsgBox('UnzipTool not found: ' + unzipTool, mbError, MB_OK)
else if not FileExists(source)
then MsgBox('File was not found while trying to unzip: ' + source, mbError, MB_OK)
else begin
{ ShellExecuteEx combined with INFINITE WaitForSingleObject }
if ShellExecuteEx(ExecInfo) then
begin
while WaitForSingleObject(ExecInfo.hProcess, 100) = WAIT_TIMEOUT { WAIT_OBJECT_0 }
do begin
AppProcessMessage;
{ InstallPage.Surface.Update; }
{ BringToFrontAndRestore; }
WizardForm.Refresh();
end;
CloseHandle(ExecInfo.hProcess);
end;
end;
end;
(This code is tested and works for me)

Call stored procedure in EF 6 Repository Pattern without output parameters

I'm working with Repository Pattern and EF6. What I need to do is to call a SP that delete records for mapping table that have nothing in common within the repository I'm calling the SP.
I've tried with
this.dbSet.SqlQuery("exec mySP #Param1, #Param2", param1, param2);
but this returns all the records from the DB of the current repository I'm in. It's like I've wrote "SELECT * FROM Group" (if I'm in GroupRepository).
My SP returns nothing since it's deleting some records and I already wasted 2 days of searching how to call the SP. I can give additional info if needed.
Can anybody help?
Finally I manage to execute my stored procedure, which was accepting a List<int> and an Id. The code looks like this:
SQL SERVER:
CREATE TYPE [dbo].[IntListType] AS TABLE
(
[Item] INT
);
GO
CREATE PROCEDURE [removeEventUsersFromEvents]
(
#EventIds [dbo].[IntListType] READONLY,
#UserId INT
)
AS
BEGIN
BEGIN Tran T1
DECLARE #query NVARCHAR(MAX)
SET NOCOUNT ON;
SET #query = 'DELETE FROM [EventUser]
WHERE [EventID] IN (SELECT Item from #EventIds) AND [UserID] = #UserId';
EXECUTE sp_executesql #query,
N'#EventIds [dbo].[IntListType] READONLY, #UserId INT',
#EventIds,
#UserId;
COMMIT Tran T1
END;
C#:
List<int> eventIdsToBeDeleted = this.dbSet...(geting some Ids from the db);
DataTable dt = new DataTable("IntListType");
dt.Columns.Add("Item", typeof(Int32));
eventIdsToBeDeleted.ForEach(id => dt.Rows.Add(id));
var eventIds = new SqlParameter("EventIds", SqlDbType.Structured);
eventIds.TypeName = "dbo.IntListType";
eventIds.Value = dt;
foreach (var user in usersToBeDeletedFromEvents)
{
var userId = new SqlParameter("UserId", SqlDbType.Int);
userId.Value = user.UserID;
this.Context.Database.SqlQuery(typeof(List<int>),
"EXEC removeCalendarEventUsersFromSpecificGroupAndEvents
#CalendarEventIds,
#UserProfileDetailId",
eventIds,
userId);
}
This will eventually return an empty List<int>.

Postgres function(via npgsql) call to ExecuteNonQuery returns -1 as result for rows affected

I have a simple function that just inserts the parameter values provided to it into columns in a table.
When I run the function via the ExecuteNonQuery() method on the command object I always get -1, even if the insert took place.
If i run the same query as a Text command it gives be the correct result of 1.
I'm new to postgresql/npgsql. Is there trick to making the function feed back the number of rows affected? Something like "set nocount off" in SQL Server?
EDIT:
The code I am using: (with npgsql 2.0.11)
var connStr = #"Server=127.0.0.1;Port=5432;User Id=postgres;Password=***;Database=Test;";
using (var conn = new NpgsqlConnection(connStr)) {
conn.Open();
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "insert_something";
cmd.CommandType = CommandType.StoredProcedure;
NpgsqlCommandBuilder.DeriveParameters(cmd);
cmd.Parameters["_id"].Value = 1;
cmd.Parameters["_val"].Value = 2;
var rowsAffected = cmd.ExecuteNonQuery();
Console.WriteLine(rowsAffected);
}
}
I haven't used Npgsql, but the documentation has an example with
the following code:
NpgsqlCommand command = new NpgsqlCommand("insert into table1 values(1, 1)", conn);
Int32 rowsaffected;
try
{
rowsaffected = command.ExecuteNonQuery();
}
If you are talking about some PostgreSQL function like this:
CREATE FUNCTION myinsert(integer) RETURNS void
LANGUAGE 'sql' AS 'INSERT INTO mytable VALUES ($1)';
and you are doing something like SELECT myinsert(1);, you can't get the number of affected rows, because you are running a SELECT and what the function does internally is opaque to you.
For ExecuteNonQuery() to get the number of rows affected, your postgresql function should return just that. An example would be:
CREATE OR REPLACE FUNCTION insert_something(_id int, _val int)
RETURNS int as $$
DECLARE count int;
BEGIN
INSERT INTO some_table (id, value) VALUES(_id, _val);
GET DIAGNOSTICS count = ROW_COUNT;
RETURN count;
END;
$$ language plpgsql;
Now if you call ExecuteNonQuery() from your code, you should get the inserted rows count.
Here's how I have implemented and its working for me without any issues:
Add an OUT Parameter to your function.
CREATE OR REPLACE FUNCTION schema.UpdateSomeValue(
IN par_updateId text,
OUT par_returnvalue INT4)
BEGIN
UPDATE schema.TableToUpdate
SET status = 1
WHERE ID = par_updateId;
GET DIAGNOSTICS par_returnvalue = ROW_COUNT;
END;
Now on the C# side
private int UpdateSomeValue()
{
var connStr = #"Server=127.0.0.1;Port=5432;UserId=postgres;Password=***;Database=Test;";
int result = -1;
using (var conn = new NpgsqlConnection(connStr)) {
conn.Open();
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "shema.UpdateSomeValue";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("par_updateId",NpgsqlTypes.NpgsqlDbType.INT, 1);
NpgsqlParameter outParm = new NpgsqlParameter("par_returnvalue",
NpgsqlTypes.NpgsqlDbType.Integer)
{
Direction = ParameterDirection.Output
};
cmd.ExecuteNonQuery();
result = Convert.ToInt32(outParm.Value);
}
}
return result;
}
PS : I tried the just ExecuteNonQuery() approach but it was always returning -1 for me (as if no rows has been affected NpgsqlDocumentation) Using above way I was able to capture the Number of rows affected from the PostgreSQL function and with OUT parameter it was easy to catch the affected rows on the client side.