SqlDataAdapter taking too long to Fill VB.NET SQL Server 2012 - sql-server

I'm working on a winform application and I'm using a table named [File] in my SQL Server database.
I have a form that views some of "[File]" fields fID and fName in a combobox named SearchName. fID for Value and fName for Display.
SearchName Combobox is bound to dataset with dataadapter filling table with fID, fName, fPhoneNumber, fBalance, so I can use fName and fID.
I have also textboxes to add new "File" data like : fName, fAge, fNationality,fSex with a Save button with another combobox showing something called "Source".
When User clicks Save the data is saved to table [File] In DB and the adapter is filled again.
The dataset tableadapter was using a stored procedure as the following:
create proc [dbo].[ReadFileData](#fid int,#filter varchar(20))
as
begin
declare #f varchar(20)=#filter;
declare #id int =#fid;
if(#id=-1)
begin
if(#f='All')
select fID,fName,fPhoneNumbers,fBalance from [File]
else
if(#f='Blocked')
select fID,fName,fNotes,fBalance,fBlockDate,uFullName
from [File],[User] where fBlocked='True' and fBlocker=[uID]
order by fBlockDate desc
else
if(#f='nonBlocked')
select fID,fName,fPhoneNumbers,fBalance from [File] where fBlocked='False'
else
if(#f='notReady')
select fID,fName,fPhoneNumbers,fBalance from [File] where fAllTestsOK='False' and fBlocked='False'
else
if(#f='Ready')
select fID,fName,fPhoneNumbers,fBalance from [File] where fAllTestsOK='True' and fBlocked='False'
else
if(#f='NegBalanced')
select fID,fName,fPhoneNumbers,fBalance from [File] where fBalance<0
end
else
select f.fID,fName,fSex,fBirthDate,fPhoneNumbers,fAddress,fNationality,fNotes,fBalance,fBlocked,(select uFullName from [User] where uid=f.fBlocker) as fBlocker,
fLastEdited,(select uFullName from [User] where [uID]=f.fEditor) as fEditor, fBlockDate from [File] f where fID=#fid
end
It was taking too much time to save and fill the combobox again. I searched over the internet and I found out the problem is called "Patamter Sniffing/spoofing", because my procedure was selecting fields based on the values of the parameter it receives. I tried different ways to solve it, but nothing worked out for me. (P.S. I am using the same SP on other forms and data is filled immediately with no problems).
I deleted the whole dataset and created a new one with a new dataadapter using new Stored Procedure, this:
create proc [dbo].[GetAllFiles]
as
begin
select fID,fName,fPhoneNumbers,fBalance from [File]
end
Now first time the save and fill is done in no time, but after that it takes like 10+ seconds to fill.
I want to know what can I do to continue using the dataadapter to fill the combobox and solve time consuming problem?
If you have any suspicions that might cause these kind of problems, please let me know.
What other code parts or even design pictures can I provide to make my problem clearer?

Thanks to #Plutonix. He wrote it in a reply, just to make it clearer.
"You should spend a few hours on MSDN. You do not need to requery/refill/rebuild a datatable when you add rows; they can be refreshed. – Plutonix"
I used DataAdapterName.Adapter.Update(DatasetName) in save button and other update places. And kept fill only in page load event.

Related

Oracle APEX - Download selected files as zip - IR/IG checkbox selection

I referred to this link create a download zip button to download files in zip format in Oracle apex latest version 22.2. It is working fine without any issues but only concern is; it downloads all the files in one zip file. Whereas my requirement is to include a checkbox on a report (either IG or IR) and to download selected files in one zip file.
Below is the table I am referring to. Its from Oracle apex sample files upload and download.
select
ID,
ROW_VERSION_NUMBER,
PROJECT_ID,
FILENAME,
FILE_MIMETYPE,
FILE_CHARSET,
FILE_BLOB,
FILE_COMMENTS,
TAGS,
CREATED,
CREATED_BY,
UPDATED,
UPDATED_BY
from EBA_DEMO_FILES
I tried searching over the internet and found few links pointing to APEX_ZIP, PL/SQL compress blob etc. But could not see any demo or working model similar to the link I provided above.
If anybody has working demo or blog,I request to share it. Many thanks.
Update: As suggested by Koen Lostrie, I am updating Page process code below:
DECLARE
l_id_arr apex_t_varchar2;
l_selected_id_arr apex_t_varchar2;
var_zip blob;
BEGIN
-- push all id values to an array
FOR i IN 1..APEX_APPLICATION.G_F03.COUNT LOOP
apex_string.push(l_id_arr,APEX_APPLICATION.G_F03(i));
FOR j IN 1 .. APEX_APPLICATION.G_F01.COUNT LOOP
IF APEX_APPLICATION.G_F01(j) = APEX_APPLICATION.G_F03(i) THEN
-- push all selected emp_id values to a 2nd array
apex_string.push(l_selected_id_arr,APEX_APPLICATION.G_F03(i));
END IF;
END LOOP;
END LOOP;
-- Create/clear the ZIP collection
APEX_COLLECTION.CREATE_OR_TRUNCATE_COLLECTION(
p_collection_name => 'ZIP');
-- Loop through all the files in the database
begin
for var_file in (select fi.filename, fi.file_blob, pr.project
from eba_demo_files fi
inner join eba_demo_file_projects pr on fi.project_id = pr.id
where fi.id in (SELECT column_value FROM table(apex_string.split(apex_string.join(l_selected_id_arr,':'),':'))))
loop
-- Add each file to the var_zip file
APEX_ZIP.ADD_FILE (
p_zipped_blob => var_zip,
p_file_name => var_file.project || '/' || var_file.filename,
p_content => var_file.file_blob );
end loop;
exception when no_data_found then
-- If there are no files in the database, handle error
raise_application_error(-20001, 'No Files found!');
end;
-- Finish creating the zip file (var_zip)
APEX_ZIP.FINISH(
p_zipped_blob => var_zip);
-- Add var_zip to the blob column of the ZIP collection
APEX_COLLECTION.ADD_MEMBER(
p_collection_name => 'ZIP',
p_blob001 => var_zip);
END;
Once page process is done, follow step 3 and 4 from the link provided in OP.
Below is the updated query:
select
ID,
ROW_VERSION_NUMBER,
PROJECT_ID,
FILENAME,
FILE_MIMETYPE,
FILE_CHARSET,
FILE_BLOB,
FILE_COMMENTS,
TAGS,
CREATED,
CREATED_BY,
UPDATED,
UPDATED_BY,
APEX_ITEM.CHECKBOX(1,ID) checkbox,
APEX_ITEM.TEXT(2,FILENAME) some_text,
APEX_ITEM.HIDDEN(3,ID) hidden_empno
from EBA_DEMO_FILES
Big Thanks to Koen Lostrie.
All credits goes to Koen Lostrie.
Thanks,
Richa
This is just an answer to the last comment - the base question was answered in the comments. The question in the comment is "how do I include APEX_ITEM.HIDDEN columns in my report without hiding the columns".
When the columns are hidden in the report, they're not rendered in the DOM, so the values do not exist when the form is posted. That is the reason you're getting the error.
However, take a step back and check what APEX_ITEM.HIDDEN generates. Add a column of type APEX_ITEM.HIDDEN to the report and inspect the column in the browser tools. It generates an input element of type "hidden", so the value is not shown in the report. So to include the column in your report but not make it visible on the screen, just concatenate it to an existing other column:
In your case, with the select from the question that would be:
select
APEX_ITEM.HIDDEN(3,ID) || APEX_ITEM.HIDDEN(2,FILENAME) || ID,
ROW_VERSION_NUMBER,
PROJECT_ID,
FILENAME,
FILE_MIMETYPE,
FILE_CHARSET,
FILE_BLOB,
FILE_COMMENTS,
TAGS,
CREATED,
CREATED_BY,
UPDATED,
UPDATED_BY,
APEX_ITEM.CHECKBOX(1,ID) checkbox
from EBA_DEMO_FILES
Note that filename can also be in a hidden element.

Access Listbox query preventing SQL Server Update Query

I'm developing an Access application and a SQL Server backend simultaneously. I have a Form with a listbox which, when a record is double clicked, opens an unbound form and loads data into it based on the record selected. When changes are made in this second form, a button initiates a pass through query that executes a stored procedure updating the details of the record in the base table in SQL Server.
Here's the thing. As long as Form1 (with the listbox) is open, the stored procedure times out without running. If I close that form, it takes less than a second. It behaves this way when run from Access, when run from management studio, and when run in management studio as a query with hard values (not a sproc with parameters).
The row source for the listbox is a linked table that references a View in SQL Server. The query within the view is a recursive common table expression of two different tables, one of which is the table being edited by the sproc. I've set the view to read only. Is there another setting that I can do to help here?
Here's the stored procedure:
PROCEDURE [dbo].[spSalesPlanUpdate]
#Salesyear numeric(4,0),
#ItemNumber varchar(20),
#Baseline int,
#Speculation int,
#Comments varchar(max)
AS
declare #SY numeric(4,0),
#ItN varchar (20),
#BL int,
#SPL int,
#CmT varchar(max)
set #SY = #Salesyear
set #ItN = #ItemNumber
set #BL = #Baseline
set #SPL = #Speculation
set #CmT = #Comments
BEGIN
SET NOCOUNT ON;
update SalesPlan
set Baseline = #BL
,Speculation = #SPL
,DateModified = getdate()
,Comments = #CmT
where SalesYear = #SY and ItemNumber = #ItN
END
I used both parameters and local variables because at first I was thinking it might be about parameter sniffing.
Here's the view the listbox is queried from:
view [dbo].[vwSalesPlan] as
with cte
as
(
select Item, year(getdate()) as SY
from vwItemsAndLiners il
union all
select ial.Item,
(cte.SY + 1)
From vwItemsAndLiners ial join cte on ial.Item = cte.Item
Where SY < (year(getdate())+ial.YearsFromProp)
)
select sp.ItemNumber, ial.Variety, ial.Size, ial.PerTray, sp.SalesYear, sp.SalesYear - ial.YearsFromProp as PropYear,
sp.SalesYear - ial.YearsFromProduction as ProductionYear,
sp.Baseline, sp.Speculation,
CEILING((CAST(SP.BASELINE AS NUMERIC (12,2)) + CAST(SP.SPECULATION AS numeric(12,2)))/IAL.PerTray)*IAL.PerTray as Total ,
sp.DateModified, ial.Segment ,'Entered' as [Status], sp.Comments
From SalesPlan sp inner join vwItemsAndLiners ial on sp.ItemNumber = ial.Item
Where ial.status = 'Sell'
union
select cte.Item, ial.Variety, ial.Size, ial.PerTray, SY, cte.sy - ial.YearsFromProp as PropYear,
cte.SY - ial.YearsFromProduction as ProductionYear,'', '', 0, null, ial.Segment , 'Not Entered', null
from cte inner join vwItemsAndLiners ial on cte.Item = ial.Item
where cte.Item not in (select ItemNumber from SalesPlan where salesplan.SalesYear = CTE.SY) and ial.Status = 'Sell'
with check option
Table being updated: SalesPlan
View that the listbox is queried from: vwSalesPlan
I realize that there's a lot of stuff here. Really, I'm just hoping this generates some ideas of why a form being open would lock the original table from an update query. Thanks!
I tried:
Indexing the views in SQL Server that provide the rowsource for the listbox, but because they contain CTE's they cannot be indexed.
lstbox.recordset.movefirst then lstbox.recordset.movelast to force access to read the entire list, but whenever the list was filtered or requeried it would throw an error saying the recordset object had changed and the movefirst command was invalid.
So I wrote this sub:
Private Sub readtheData()
Dim i As Integer
i = Me.lstSalesPlan.ListCount
End Sub
Simply forcing it to count the records every time the form was loaded or the query behind the listbox was filtered forced access to release the lock. Hope this helps somebody down the road!

TableAdapter.Insert (into ACCESS DB) get current Seed value for ID

I am trying to alter an existing programm in VB , I am not experienced in this language , but unfortunately I cannot convert it for now.
I created the DB Connections with the Designer , which automatically created the BindingSource, TableAdapter , DataSet .
I insert something into this table like this :
Me.Validate()
myBindingSource.EndEdit()
myTableAdapter.Insert(1, 1, "test", 100, Now, 1, Now)
I would now like to get CURRENT_SEED valuer for the ID field ( which is Autoincrement )
can I do it somehow here without making some extra connection , is it returned somewhere ?
Regards
Robert
If you want to use table adapters for ease, just created a "Select Max(ID) From myTable" scalar query then just call it to get the last value.
int resultID = myTableAdapter.GetLastID();

After Update, Insert Trigger not working on Update SQL Server VB.net

I am building a personal comic book database and am having an issue with one of my SQL Server triggers.
My main comic entry (tabbed) form has a combo box for cover prices.
When the user clicks submit and inserts a comic into the database (comic_books table) on the comics entry page, I have a trigger that adds the cover price the user entered to a separate table (comic_prices table.) if the entry does not exist. This is working just fine.
However, I have a second tab ('Edit Comic') where the user can update an already inserted comic which uses a simple update script.
The user is able to change or add a new cover price of said comic from this tab also.
The issue I am having is that when the user clicks the 'Update Comic' button from the 'Edit Comic' tab, this newly entered comic price is not being inserted in the comic_prices table if it does not exist. So it looks like my trigger is only firing on my insert script and not on my update script.
Again, I have the trigger to only insert if the entry does not exist in the cover_prices table, otherwise it does nothing.
Please see my 'AFTER UPDATE, INSERT' trigger for this below and please let me know if you need any more information!
I appreciate any pointers or critiques!
DECLARE #cover_price varchar(50)
select #cover_price = cover_price from comic_books
If exists (SELECT cover_price FROM comic_prices where cover_price = #cover_price )
Begin
Return
End
IF not EXISTS (SELECT cover_price FROM comic_prices where cover_price = #cover_price)
INSERT INTO comic_prices(cover_price)VALUES(#cover_price)
UPDATE 04/22/17
After two or so weeks, I finally figured it out! I ended up making two separate triggers, one for the insert and another for the update. I kept the insert the same, however, the update looks like this:
DECLARE #publisher_name varchar(50)
--declare #comic_id bigint
select #publisher_name = inserted.issue_publisher from inserted
select #comic_id = comic_id from comic_books
If exists (select publisher_name from comic_publishers where publisher_name = #publisher_name)
Begin
return
End
IF not EXISTS (select publisher_name from comic_publishers where publisher_name = #publisher_name)
INSERT INTO comic_publishers (publisher_name)VALUES(#publisher_name)
I needed to tell the trigger to look for the inserted publisher!

F# FSharp.Data.SqlClient not recognizing multiple return tables from Stored Procedure

I am not sure if this is possible but I have not been able to come across clear documentation for this use case. I am using F# 4 and the FSharp.Data.SqlClient library to connect to SQL Server 2016. I am wanting to call a stored procedure that returns multiple tables and turn those tables into the corresponding records. In this case the first table is made up of items and the second table is made up of customers.
My instinct is that it should look something like this:
let items, customers = cmd.Execute()
My gut is that items would be an IEnumerable<item> and customers would be an IEnumerable<customer> where item and customer are both Record types. What it appears is happening though is that FSharp.Data.SqlClient is only seeing the first returned table from the stored procedure. I am working on a SQL Server 2016 Developer instance. Here is the T-SQL to setup the example:
create table Item (
ItemID int identity(1, 1) primary key,
ItemName nvarchar(50)
)
go
create table Customer (
CustomerID int identity(1, 1) primary key,
CustomerName nvarchar(50)
)
go
insert into Item (ItemName) values ('A');
insert into Item (ItemName) values ('B');
insert into Item (ItemName) values ('C');
insert into Customer (CustomerName) values ('Gary');
insert into Customer (CustomerName) values ('Sergei');
insert into Customer (CustomerName) values ('Elise');
go
create procedure dbo.ExampleProcedure
as
begin
set nocount on;
select
ItemID,
ItemName
from Item
select
CustomerID,
CustomerName
from Customer
end;
And here is the F# script that I am testing with. It shows what I would like to be able to do but I get a compile error on the last line:
#r "../packages/FSharp.Data.SqlClient.1.8.2/lib/net40/FSharp.Data.SqlClient.dll"
#r "../packages/FSharp.Data.2.3.2/lib/net40/FSharp.Data.dll"
#r "System.Xml.Linq.dll"
open FSharp.Data
[<Literal>]
let connStr =
"Data Source=**connection string**;"
type queryExample = SqlProgrammabilityProvider<connStr>
do
use cmd = new queryExample.dbo.ExampleProcedure(connStr)
let items, customers = cmd.Execute()
I am wanting items to correspond to the first returned table and customers to correspond to the second returned table. The intellisense suggests that FSharp.Data.SqlClient is only seeing the first table. When I hover over cmd.Execute() the popup says "This expression was expected to have type 'a*'b but here has type System.Collections.Generic.IEnumerable<SqlProgrammabilityProvider<...>.dbo.ExampleProcedure.Record>". If I do the following I get access to the Items query in the stored procedure:
// Learn more about F# at http://fsharp.org. See the 'F# Tutorial' project
// for more guidance on F# programming.
#r "../packages/FSharp.Data.SqlClient.1.8.2/lib/net40/FSharp.Data.SqlClient.dll"
#r "../packages/FSharp.Data.2.3.2/lib/net40/FSharp.Data.dll"
#r "System.Xml.Linq.dll"
open FSharp.Data
[<Literal>]
let connStr =
"Data Source=**connection string**;"
type queryExample = SqlProgrammabilityProvider<connStr>
do
use cmd = new queryExample.dbo.ExampleProcedure(connStr)
for item in cmd.Execute() do
printfn "%A" item.ItemID
Is this even possible? Is my approach wrong? I could not find clear documentation on this use case but I thought it would be common enough it would be covered.
Update
Just to clarify what I am trying to achieve I am showing how I solve this in C#. In C# I create a DataSet object and populate it with the results of the Stored Procedure. From there I pick out the individual tables to work with. After extracting the tables I then use LINQ to transform the rows into the corresponding objects. It often looks something like the following:
using System.Data;
using System.Data.SqlClient;
var connStr = "**connection string**"
var sqlConnection = new SqlConnection(connStr );
var sqlCommand = new SqlCommand("ExampleProcedure", sqlConnection);
sqlCommand.CommandType = CommandType.StoredProcedure;
var dataSet = new DataSet();
var adapter = new SqlDataAdapter(sqlCommand);
adapter.Fill(dataSet);
var itemsTable = dataSet.Tables[0];
// Turn the itemsTable into a List<Item> using LINQ here
var customersTable = dataSet.Tables[1];
// Turn the customersTable into List<Customer> using LINQ here
I find this to be overly verbose for such a simple thing as extracting the individual tables but perhaps I am too sensitive to code clutter. I know that F# must have a more elegant and terse way to express this.
I don't know F#, however this is a data access problem.
When a stored procedure returns multiple resultsets, you need to access they in sequence, one by one.
cmd.ExecuteReader() returns an instance of a datareader pointing to the first resultset. You need to process this resultset, may be filling a list with instances of a custom class, than you call the method "NextResult" and you will have access to the next resultset and so on.
A reference for the method "NextResult": https://msdn.microsoft.com/pt-br/library/system.data.sqlclient.sqldatareader.nextresult(v=vs.110).aspx

Resources