Cannot implicitly convert type 'System.Data.Linq.ISingleResult<CustomeProcedureName> to 'int' - asp.net

Sorry for this simple question .
I have a Stored Procedure that return an int value , I'm trying to call this sp from my asp.net linq to sql project .
int currentRating = db.sproc_GetAverageByPageId(pageId);
But i get this error :
Cannot implicitly convert type `'System.Data.Linq.ISingleResult<PsychoDataLayer.sproc_GetAverageByPageId> to 'int' .`
Edit 1
The solution that friends implied didn't work . All the time it return 0
For more information i put my stored procedure here :
ALTER procedure [dbo].[sproc_GetAverageByPageId](
#PageId int )
as
select (select sum(score) from votes where pageId = #PageId)/(select count(*) from votes where pageId=#PageId)

You should inspect the ReturnValue property.
Perhaps the following works better?
int currentRating = (int)db.sproc_GetAverageByPageId(pageId).ReturnValue;
Update: since your stored proc returns a resultset instead of using a return statement the actual data will be available as an element in the enumerable returned by db.sproc_GetAverageByPageId(pageId). If you inspect the ISingleResult<T> type, you'll see that it inherits IEnumerable<T> which indicates that you can enumerate the object to get to the data, each element being of type T.
Since the sproc does a SELECT SUM(*) ... we can count on the resultset to always contain one row. Thus, the following code will give you the first (and only) element in the collection:
var sumRow = db.sproc_GetAverageByPageId(pageId).Single();
Now, the type of sumRow will be T from the interface definition, which in your case is PsychoDataLayer.sproc_GetAverageByPageId. This type hopefully contains a property that contains the actual value you are after.
Perhaps you can share with us the layout of the PsychoDataLayer.sproc_GetAverageByPageId type?

Looks like you're actually after the ReturnValue. You may need to cast it to System.Data.Linq.ISingleResult if it isn't already, then cast ReturnValueto int.

This is actually returning an ISingleResult
int currentRating = (int) db.sproc_GetAverageByPageId(pageId).ReturnValue;
Change your sp to :
ALTER procedure [dbo].[sproc_GetAverageByPageId](
#PageId int )
as
return (select sum(score) from votes where pageId = #PageId)/(select count(*) from votes where pageId=#PageId)

one more thing you can do:
ALTER procedure [dbo].[sproc_GetAverageByPageId](#PageId int ) as
select (select sum(score) from votes where pageId = #PageId)/(SELECT * FROM votes where pageId=#PageId)
WRITE >>
"select * From"<< instead of "select Count(*)"
select (select sum(score) from votes where pageId = #PageId)/(SELECT * FROM votes where pageId=#PageId)
and after that:
int currentRating = (int)db.sproc_GetAverageByPageId(pageId).count();

Related

sql lite update query list parameter issue

I have a simple sql lite query using room like this.
#Query("UPDATE MYTABLE SET CAT_ID = :idCata WHERE MYTABLE_ID IN (:listIds)")
int updateAll(long idCata, String listIds);
Where CAT_ID is defined as a nullable foreign key and MYTABLE_ID is primary key for MYTABLE.
All is working if i use one value in listIds parameter.
If i put something like "1,5" this does not update the rows in the database. If i use "1" or "5" as single value in listIds, all is ok.
I have nothing in logcat or something like issue in logs.
Can someone explain me why ?
EDIT : I posted answer
I believe that the issue is that 1,5 will be enclosed in single quotes and will be treated as a string. So only rows that have 1,5 as the value would be updated.
When you use IN the values should in an array Room will then build the correct IN clause. So you want :-
#Query("UPDATE MYTABLE SET CAT_ID = :idCata WHERE MYTABLE_ID IN (:listIds)")
int updateAll(long idCata, String[] /*<<<<<<<<<<*/ listIds);
Obviously you need to split listIds into the array.
or
int updateAll(long idCata,listIds.split(','));
which does the split
Here is the solution, note i used long array because the query is updating foreign key values which cannot be typed as string.
I think it is more elegant and safer. So the final code is :
String[] ids = listIds.split(",");
long[] idsForQuery = new long[ids.length];
try{
for(int i = 0; i < ids.length; i++){
idsForQuery[i] = Long.parseLong(ids[i]);
}
mDao.updateAll(idCata, idsForQuery);
}
catch(NumberFormatException e){
// something wrong with ids type !!
}
And in the dao, the sql lite query.
#Query("UPDATE MYTABLE SET CAT_ID = :idCata WHERE MYTABLE_ID IN (:listIds)")
int updateAll(long idCata, long[] listIds);
Thanks to MikeT for the help.

Pass parameter that will return all rows

I'm working on an ASP.NET application that will call a simple Stored Procedure. The SP looks something like this:
Select *
from empTable
where ID = #ID AND Department = #DeptID
and status = #status
and role = #role
The ASP.NET application will pass a value to the each parameter in the stored procedure. Every parameter can be null or have a value. However, if the user enter nothing (null or empty), it should return everything in that empTable as if Select * from empTable with no Where clause.
However, due to the orders from the management:
I CANNOT change the code in ASP.NET application.
I CANNOT use dynamic SQL.
I'm only allowed to modify the stored procedure.
Is there any way I can work around this?
Make the parameter optional by changing the WHERE clause and assign a default value.
CREATE PROCEDURE MyProc
#ID INT = NULL
AS
Select * from empTable where ID = ISNULL(#ID, ID);
Case statements work...use case to set 1 = 1 when #id = 'all' (or whatever you want the #id to equal for all)
Select * from empTable where
case when #id = 'all' then 1 else id end
=
case when #id = 'all' then 1 else #id
JodyT's answer is better...this works, but not as pretty

SQLite query to find primary keys

In SQLite I can run the following query to get a list of columns in a table:
PRAGMA table_info(myTable)
This gives me the columns but no information about what the primary keys may be. Additionally, I can run the following two queries for finding indexes and foreign keys:
PRAGMA index_list(myTable)
PRAGMA foreign_key_list(myTable)
But I cannot seem to figure out how to view the primary keys. Does anyone know how I can go about doing this?
Note: I also know that I can do:
select * from sqlite_master where type = 'table' and name ='myTable';
And it will give the the create table statement which shows the primary keys. But I am looking for a way to do this without parsing the create statement.
The table_info DOES give you a column named pk (last one) indicating if it is a primary key (if so the index of it in the key) or not (zero).
To clarify, from the documentation:
The "pk" column in the result set is zero for columns that are not
part of the primary key, and is the index of the column in the primary
key for columns that are part of the primary key.
Hopefully this helps someone:
After some research and pain the command that worked for me to find the primary key column name was:
SELECT l.name FROM pragma_table_info("Table_Name") as l WHERE l.pk = 1;
For the ones trying to retrieve a pk name in android, and while using the ROOM library.
#Oogway101's answer was throwing an error: "no such column [your_table_name] ... etc.. etc...
my way of query submition was:
String pkSearch = "SELECT l.name FROM pragma_table_info(" + tableName + ") as l WHERE l.pk = 1;";
database.query(new SimpleSQLiteQuery(pkSearch)
I tried using the (") quotations and still error.
String pkSearch = "SELECT l.name FROM pragma_table_info(\"" + tableName + "\") as l WHERE l.pk = 1;";
So my solution was this:
String pragmaInfo = "PRAGMA table_info(" + tableName + ");";
Cursor c = database.query(new SimpleSQLiteQuery(pragmaInfo));
String id = null;
c.moveToFirst();
do {
if (c.getInt(5) == 1) {
id = c.getString(1);
}
} while (c.moveToNext() && id == null);
Log.println(Log.ASSERT, TAG, "AbstractDao: pk is: " + id);
The explanation is that:
A) PRAGMA table_info returns a cursor with various indices, the response is atleast of length 6... didnt check more...
B) index 1 has the column name.
C) index 5 has the "pk" value, either 0 if it is not a primary key, or 1 if its a pk.
You can define more than one pk so this will not bring an accurate result if your table has more than one (IMHO more than one is bad design and balloons the complexity of the database beyond human comprehension).
So how will this fit into the #Dao? (you may ask...)
When making the Dao "abstract" you have access to a default constructor which has the database in it:
from the docummentation:
An abstract #Dao class can optionally have a constructor that takes a Database as its only parameter.
this is the constructor that will grant you access to the query.
There is a catch though...
You may use the Dao during a database creation with the .addCallback() method:
instance = Room.databaseBuilder(context.getApplicationContext(),
AppDatabase2.class, "database")
.addCallback(
//You may use the Daos here.
)
.build();
If you run a query in the constructor of the Dao, the database will enter a feedback loop of infinite instantiation.
This means that the query MUST be used LAZILY (just at the moment the user needs something), and because the value will never change, it can be stored. and never re-queried.

Ordering SQL Server results by IN clause

I have a stored procedure which uses the IN clause. In my ASP.NET application, I have a multiline textbox that supplies values to the stored procedure. I want to be able to order by the values as they were entered in the textbox. I found out how to do this easily in mySQL (using FIELD function), but not a SQL Server equivalent.
So my query looks like:
Select * from myTable where item in #item
So I would be passing in values from my application like '113113','112112','114114' (in an arbitrary order). I want to order the results by that list.
Would a CASE statement be feasible? I wouldn't know how many items are coming in the textbox data.
How are you parameterising the IN clause?
As you are on SQL Server 2008 I would pass in a Table Valued Parameter with two columns item and sort_order and join on that instead. Then you can just add an ORDER BY sort_order onto the end.
From KM's comment above...
I know you didn't state it is comma seperated, but if it was a CSV or even if you have it space seperated you could do the following.
DECLARE #SomeTest varchar(100) --used to hold your values
SET #SomeTest = (SELECT '68,72,103') --just some test data
SELECT
LoginID --change to your column names
FROM
Login --change to your source table name
INNER JOIN
( SELECT
*
FROM fn_IntegerInList(#SomeTest)
) n
ON
n.InListID = Login.LoginID
ORDER BY
n.SortOrder
And then create fn_IntegerInList():
CREATE FUNCTION [dbo].[fn_IntegerInList] (#InListString ntext)
RETURNS #tblINList TABLE (InListID int, SortOrder int)
AS
BEGIN
declare #length int
declare #startpos int
declare #ctr int
declare #val nvarchar(50)
declare #subs nvarchar(50)
declare #sort int
set #sort=1
set #startpos = 1
set #ctr = 1
select #length = datalength(#InListString)
while (#ctr <= #length)
begin
select #val = substring(#InListString,#ctr,1)
if #val = N','
begin
select #subs = substring(#InListString,#startpos,#ctr-#startpos)
insert into #tblINList values (#subs, #sort)
set #startpos = #ctr+1
end
if #ctr = #length
begin
select #subs = substring(#InListString,#startpos,#ctr-#startpos)
insert into #tblINList values (#subs, #sort)
end
set #ctr = #ctr +1
set #sort = #sort + 1
end
RETURN
END
This way your function creates a table that holds a sort order namely, SortOrder and the ID or number you are passing in. You can of course modify this so that you are looking for space rather then , values. Otherwise Martin has the right idea in his answer. Please note in my example I am using one of my tables, so you will need to change the name Login to whatever you are dealing with.
the same way you concatenate ('113113','112112','114114') to pass to the sql sentence in the where clausule you can concatenate
order by
case item
when '113113' then 1
when '112112' then 2
when '114114' then 3
end
to pass to your order by clausule

Passing a IS NOT NULL through a sqlparameter

I have a query in sql server 2008. That I want to either pass a value from the dropdownlist or IS NOT NULL (so it shows all of the values). What's the best way to handle this? I know you can't pass the string "IS NOT NULL" to the parameter. I'm a bit stuck on this one.
ASP.NET 3.5 and SQL Server 2008.
Assuming this is a stored procedure, say your parameter is called #Param1, have the parameter set to NULL to indicate IS NOT NULL, as follows:
SELECT ...
FROM ...
WHERE (
(#Param1 IS NULL AND field1 IS NOT NULL)
OR (field1 = #Param1)
)
Suggested by GSerg
Testing ISNULL(#Param1, field1) = field1 with the following:
DECLARE #test1 nvarchar(10) = 'testing',
#test2 nvarchar(10) = NULL; -- or 'random' or 'testing'
SELECT 1
WHERE ISNULL(#test2, #test1) = #test1;
Computations are showing as 1 for each case. This appears to be a better solution than my original answer.
You can use the like operator:
select * from table1 where name like #param
setting #param to % if you want not null values. But then you have to escape the %.

Resources