get multiple string outputs from stored procedure using entity framework - c#

The following stored procedure displays three strings and a table row result as output.
Is there any way we can display all the results on a mvc view output panel using entity framework?
I could see the first string result in the code below. But is there anyway to get the other two select string outputs and
the table row result.
private CustomerEntities db = new CustomerEntities();
public ActionResult Index()
{
var results = db.usp_CustomerData("124544", 1500);
var abc = results.ToList();
return View();
}
ALTER PROCEDURE [dbo].[usp_CustomerData]
#CustomerID varchar(6),
#MinsBack int
AS
BEGIN
DECLARE #Count int
SET #Count = (SELECT Count(*)
FROM Customer WITH (NOLOCK)
WHERE CustomerID = #CustomerID AND
DATEDIFF(mi, ReceivedAt, GETUTCDATE()) < #MinsBack)
IF (#Count = 1)
SELECT 'Ok: 1 message in Customer table'
ELSE
SELECT 'ERROR: Expected 1 message in Customer table, but found ' + CONVERT(varchar(3), #Count) + ' messages.'
SET #Count = (SELECT Count(*)
FROM CustomerDetails WITH (NOLOCK)
WHERE CustomerID = #CustomerID AND
DATEDIFF(mi, LastUpdatedAt, GETDATE()) < #MinsBack)
IF (#Count = 1)
SELECT 'Ok: 1 record in CustomerDetails table'
ELSE
SELECT 'ERROR: Expected 1 record in CustomerDetails table, but found ' + CONVERT(varchar(3), #Count) + ' records.'
SET #Count = (SELECT Count(*)
FROM CustomerProduct WITH (NOLOCK)
WHERE CustomerID = #CustomerID AND
DATEDIFF(mi, LastUpdatedAt, GETDATE()) < #MinsBack)
IF (#Count = 1)
SELECT 'Ok: 1 record in CustomerProduct table'
ELSE
SELECT 'ERROR: Expected 1 record in CustomerProduct table, but found ' + CONVERT(varchar(3), #Count) + ' records.'
SELECT *FROM Customer where customerID = #CustomerID
END

As suggestion you could create a temporary table in your SQL script which will be used as temporary store.
CREATE TABLE #Results
(
Message VARCHAR(512)
)
Instead of a direct SELECT in each IF or ELSE you should insert the string into the temp table.
At the end you could reach your goal to get all inserted strings to return them by:
SELECT * FROM #Results
To get customers - like you do at the end - you should trigger a new query to database.
Depending on your case you should consider to querying the database by data context instead of querying the database by store procedures.

You need to do something as suggest in this link but I summarized below
For each results set you will need to do a reader.NextResult();
var someReturnObject = new ResultObject();
using (var context = new LinqPadDbContext(#"Server=localhost\SQLEXPRESS;Database=StackOverflow;Trusted_Connection=True;"))
{
var cmd = context.Database.Connection.CreateCommand();
cmd.CommandText = "[dbo].[GetSomeData]";
try
{
context.Database.Connection.Open();
var reader = cmd.ExecuteReader();
var result1 = ((IObjectContextAdapter)context).ObjectContext.Translate<string>(reader);
someResultObject.Text1 = result1.First();
//for each extra result, start here
reader.NextResult();
var users = ((IObjectContextAdapter)context).ObjectContext.Translate<User>(reader);
someResultObject.Users = users.Select(x => x);
//stop here
}
finally
{
context.Database.Connection.Close();
}
}

Related

Index out of range on column from inner join condition

I am getting a index out of range error when trying to get a string value from a datareader. The column USER_ROLE which is the only column from a INNER JOIN condition. It was working and for some reason has now started throwing this index out of range error. I've verified the actual stored procedure works via SSMS and the column is being returned.
Below is the code for the stored procedure
ALTER PROCEDURE [dbo].[usp_GetUsersLogonInformation]
(
-- inactive = 0, active = 1, all = 2
#active int = 2
)
AS
BEGIN
DECLARE #whereClauseNeeded bit = 1
DECLARE #whereClause nvarchar(100) = concat(' WHERE usr.ACTIVE = ', #active)
DECLARE #sqlCmd nvarchar(max)= 'SELECT
usr.USER_PK,
usr.PRINCIPAL_ID,
usr.AA_USER_FK,
usr.FIRST_NAME,
usr.LAST_NAME,
usr.[USER_NAME],
usr.EMAIL_ADDRESS,
usr.ACTIVE,
usr.LV_USER_ROLE_FK,
lvur.USER_ROLE,
usr.CREATED_BY,
usr.CREATED_SYSDATE
FROM dbo.USERS usr
INNER JOIN dbo.LV_USER_ROLES lvur ON lvur.LV_USER_ROLE_PK = usr.LV_USER_ROLE_FK'
IF #active = 0 OR #active = 1
BEGIN
set #sqlCmd = concat(#sqlCmd, #whereClause)
END
EXEC sp_executesql #sqlCmd
END
the c# code retrieving the data
using (SqlConnection dbConn = theVoiceSqlHelpers.GetDbConnection())
{
using (SqlCommand sqlCmd = new SqlCommand(USP_GET_USER_INFO, dbConn))
{
sqlCmd.CommandType = CommandType.StoredProcedure;
sqlCmd.Parameters.AddWithValue("#whereClause",string.Format("USER_NAME = \'{0}\'", txbxUserName.Text));
SqlDataReader dr = sqlCmd.ExecuteReader();
while (dr.Read())
{
user = new Tbl_Users();
user.USER_PK = dr.GetInt32(dr.GetOrdinal("USER_PK"));
user.PRINCIPAL_ID = dr.GetInt32(dr.GetOrdinal("PRINCIPAL_ID"));
user.AA_USER_FK = dr.GetInt32(dr.GetOrdinal("AA_USER_FK"));
user.FIRST_NAME = dr.GetString(dr.GetOrdinal("FIRST_NAME"));
user.LAST_NAME = dr.GetString(dr.GetOrdinal("LAST_NAME"));
user.USER_NAME = dr.GetString(dr.GetOrdinal("USER_NAME"));
user.EMAIL_ADDRESS = dr.GetString(dr.GetOrdinal("EMAIL_ADDRESS"));
user.ACTIVE = dr.GetBoolean(dr.GetOrdinal("ACTIVE"));
user.LV_USER_ROLE_FK = dr.GetInt32(dr.GetOrdinal("LV_USER_ROLE_FK"));
user.USER_ROLE = dr.GetString(dr.GetOrdinal("USER_ROLE"));
user.CREATED_BY = dr.GetString(dr.GetOrdinal("CREATED_BY"));
user.CREATED_SYSDATE = dr.GetDateTime(dr.GetOrdinal("CREATED_SYSDATE"));
}
dr.Close();
}
}
I have ensure the column name is correct however I am now stuck at this new found exception.
Has anyone seen this behavior before. My apologies if I am overlooking and obvious but could use an extra set of eyes on this.
LV_USER_ROLES Table
USERS Table
Charlieface's comment resolved the exception. In this database there is 2 similiar named usp's and I was calling the wrong one.

Correct query not working using MySqlDataReader

So I'm trying to figure out of this, in particular I have this query that perfectly works using PhpMyAdmin:
SELECT tt.team_id, (CASE WHEN t.id IS NULL THEN 0 ELSE 1 END) as exist FROM(SELECT 13048 as team_id UNION ALL SELECT 17058 UNION ALL SELECT 38809 UNION ALL SELECT 8216 UNION ALL SELECT 5466) tt LEFT JOIN team t on t.id = tt.team_id WHERE t.id IS NULL OR t.update_at < DATE_SUB(CURRENT_DATE, INTERVAL 7 DAY)
Anyway, I get this error from Visual Studio:
MySql.Data.MySqlClient.MySqlException: 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' UNION ALL SELECT 17058 UNION ALL SELECT 38809 UNION ALL SELECT 8216 UNION ALL ' at line 1'
This error is retured on:
using (MySqlDataReader reader = command.ExecuteReader())
I setup the query in this way:
command.CommandText = "SELECT tt.team_id, " +
"(CASE WHEN t.id IS NULL THEN 0 ELSE 1 END) as exist " +
"FROM(SELECT #first as team_id #others) tt LEFT JOIN team t on t.id = tt.team_id " +
"WHERE t.id IS NULL OR " +
"t.update_at < DATE_SUB(CURRENT_DATE, INTERVAL 7 DAY)";
command.Parameters.Add("#first", MySqlDbType.Int32).Value = teams.First().Id;
command.Parameters.Add("#others", MySqlDbType.String).Value = string.Concat(teams.Skip(1).Select(c => " UNION ALL SELECT " + c.Id));
Someone could help me?
This is how I would build a dynamic list of parameters to pass to your query.
Warning, not tested, but this should produce the expected output
// Command text with a placeholder where we insert the dynamic text
string cmd = #"SELECT tt.team_id,
(CASE WHEN t.id IS NULL THEN 0 ELSE 1 END) as exist
FROM (SELECT {texttoreplace}) tt
LEFT JOIN team t on t.id = tt.team_id WHERE t.id IS NULL
OR t.update_at < DATE_SUB(CURRENT_DATE, INTERVAL 7 DAY)";
int prmCounter = 1;
// Where we keep the text to insert at the appropriate place
StringBuilder unions = new StringBuilder();
// Where we keep the parameters to add at the MySqlCommand
List<MySqlParameter> prms = new List<MySqlParameter>();
// First parameter
MySqlParameter pr = new MySqlParameter("#first", MySqlDbType.Int32) { Value = teams.First().id};
prms.Add(pr);
unions.Append($" #first as team_id ");
// Loop over your IDs and build parameters and text
foreach (var t in teams.Skip(1))
{
// Giving an unique name to the parameter
string placeholder = "#p" + prmCounter;
unions.Append($" UNION ALL SELECT {placeholder}");
pr = new MySqlParameter(placeholder, MySqlDbType.Int32) { Value = t.id};
prms.Add(pr);
prmCounter++;
}
// Add all the required parameters
command.Parameters.AddRange(prms.ToArray());
// Replace the placeholder with the built text
cmd = cmd.Replace("{texttoreplace}", unions.ToString());

Update Each Exisiting Row of SQL Server Table Using Loop

I'm trying to update a certain column for each row in my SQL Server table, using ASP.NET, C#.
When this code is executed, I want the OrderNo of the first row in the column to be = 1. From then on, I want the OrderNo to increment by 1 for the other existing rows in the table.
At the moment, I can update the OrderNo of one row, however I can't get a loop to properly read through all the rows & increment as I would like.
Here is the structure of my table
And below is my C#:
con.Open();
SqlCommand cmdUpdateOrderNo;
cmdUpdateOrderNo = new SqlCommand("UPDATE tblImages SET [OrderNo]=#O WHERE [OrderNo] = 2;", con);
cmdUpdateOrderNo.Parameters.AddWithValue("#O", 4);
cmdUpdateOrderNo.ExecuteNonQuery();
Here is the reason I need to update the OrderNo:
protected void Timer1_Tick(object sender, EventArgs e)
{
int i = (int)ViewState["ImageDisplayed"];
i = i + 1;
ViewState["ImageDisplayed"] = i;
DataRow imageDataRow = ((DataSet)ViewState["ImageData"]).Tables["image"].Select().FirstOrDefault(x => x["order"].ToString() == i.ToString());
if (imageDataRow != null)
{
Image1.ImageUrl = "~/MyImages/" + imageDataRow["name"].ToString();
lblImageName.Text = imageDataRow["name"].ToString();
lblImageOrder.Text = imageDataRow["order"].ToString();
lblImageDesc.Text = imageDataRow["Desc"].ToString();
}
else
{
SetImageUrl();
}
}
private void SetImageUrl()
{
DataSet ds = new DataSet();//Creating a dataset
SqlDataAdapter da = new SqlDataAdapter("SELECT Name, [Order], [Desc] FROM tblImages", con);
da.Fill(ds, "image");
ViewState["ImageData"] = ds;//storing the dataset in a ViewState variable
ViewState["ImageDisplayed"] = 1;//storing order number of the image currently displayed
DataRow imageDataRow = ds.Tables["image"].Select().FirstOrDefault(x => x["order"].ToString() == "1");
Image1.ImageUrl = "~/MyImages/" + imageDataRow["name"].ToString();
lblImageName.Text = imageDataRow["name"].ToString();
lblImageOrder.Text = imageDataRow["order"].ToString();
lblImageDesc.Text = imageDataRow["Desc"].ToString();
}
I agree with #Jamiec on this that it seems like a bad idea, but you don't need a loop if it's really what you want to do. Here's an example using a CTE and a Window Function.
Example
WITH T AS
( SELECT
*,
ROW_NUMBER() OVER (ORDER BY ID) as RN
FROM YourTable
)
/* this shows you the results of the CTE,
specifically the ROW_NUMBER()
which will replace the OrderNo in the code below */
SELECT * FROM T
Runing This WIll Update Your Table
WITH T AS
( SELECT
*,
ROW_NUMBER() OVER (ORDER BY ID) as RN
FROM YourTable
)
UPDATE T
SET OrderNo = RN
When dealing with SQL you almost never want to be writing loops.
Try changing your command to this
; with cte as
(
select *, row_number() over (order by ID) as rn
from tblImages
)
update tblImages
set OrderNo = rn
from cte

Only show values of combobox like "love"?

I created a store procedure to select all values of the table.
But I want in C# application, combobox only show values start like love keyword.
Example:
love love
love king
love soft
Don't show item:
long time
union all
My code:
public void HienThiLoaiBCao()
{
LovetoDAL cal = new LovetoDAL();
string keyword = "BC";
int i = cbxTenBaoCao.FindString(keyword);
if (i == -1)
return;
else
{
var dt = cal.Love_GetByTop("", "", "ID DESC");
cbxTenBaoCao.DataSource = dt;
cbxTenBaoCao.DisplayMember = "lover";
cbxTenBaoCao.ValueMember = "lover";
}
}
public DataTable Love_GetByTop(string Top, string Where, string Order)
{
using (var cmd = new SqlCommand("sq_Love_GetByTop", GetConnection()))
{
cmd.CommandType = CommandType.StoredProcedure;
var da = new SqlDataAdapter(cmd);
cmd.Parameters.Add(new SqlParameter("#Top", Top));
cmd.Parameters.Add(new SqlParameter("#Where", Where));
cmd.Parameters.Add(new SqlParameter("#Order", Order));
var dt = new DataTable();
da.Fill(dt);
return dt;
}
}
USE [LEO]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[sq_Love_GetByTop]
#Top nvarchar(10),
#Where nvarchar(500),
#Order nvarchar(500)
AS
Declare #SQL as nvarchar(500)
Select #SQL = 'SELECT top (' + #Top + ') * FROM [Love]'
if len(#Top) = 0
BEGIN
Select #SQL = 'SELECT * FROM [Love]'
END
if len(#Where) >0
BEGIN
Select #SQL = #SQL + ' Where ' + #Where
END
if len(#Order) >0
BEGIN
Select #SQL = #SQL + ' Order by ' + #Order
END
EXEC (#SQL)
Thanks.
One option is to filter out the records that starts with love from your DataTable. You can either use Select method on DataTable directly OR use RowFilter property on default DataView of the table and then bind the filtered results to your combo box.
Something like this with DataView -
DataView dv = dt.DefaultView;
//Apply your filter on data view, for records starting with `love`
dv.RowFilter = "lover like 'love*'";
//and bind you combo box with the data view
cbxTenBaoCao.DataSource = dv;
Rest of the code would be as is.
More on filtering result sets -
http://www.csharp-examples.net/dataview-rowfilter/
https://msdn.microsoft.com/en-us/library/system.data.datatable.select%28v=vs.110%29.aspx
i did not try this code, it's a long time since i code c#.
//get the values from your stored procedure
List<string> values = task.storedProcedures();
//remove items that doesn't start with "love"
values = values.Where(item => item.someValues.StartsWith("love"))
Hope this helps

cannot find table 0 in c# asp.net

if (ds.Tables[0].Rows.Count > 0)
{
txtid.Text = ds.Tables[0].Rows[0]["id"].ToString();
txttamil.Text = ds.Tables[0].Rows[0]["Tamil"].ToString();
txtenglish.Text = ds.Tables[0].Rows[0]["English"].ToString();
txtmaths.Text = ds.Tables[0].Rows[0]["Maths"].ToString();
txtscience.Text = ds.Tables[0].Rows[0]["Science"].ToString();
txtsocialscience.Text = ds.Tables[0].Rows[0]["SocialScience"].ToString();
}
}
In the above showed error 'cannot find table 0'.
When i enter invalid id, it need to show "ID does not exist".
May i know, what my mistake in my code?
stored procedure:
ALTER PROCEDURE sp_studentresult
(
#id int,
#output varchar(50) output,
#id_student varchar(50)
)
AS
IF EXISTS (SELECT * FROM student WHERE id=#id_student)
BEGIN
SELECT * from studentresult where id_student=#id
END
ELSE
BEGIN
SET #output='Doesn not EXIST'
End
any help would be highly appreciated.
Thanks,
There is no point on complicating your sp with logic.
Why don't you just check if the query has returned any data?
if (ds.Tables[0].Rows.Count > 0)
{
txtid.Text = ds.Tables[0].Rows[0]["id"].ToString();
txttamil.Text = ds.Tables[0].Rows[0]["Tamil"].ToString();
txtenglish.Text = ds.Tables[0].Rows[0]["English"].ToString();
txtmaths.Text = ds.Tables[0].Rows[0]["Maths"].ToString();
txtscience.Text = ds.Tables[0].Rows[0]["Science"].ToString();
txtsocialscience.Text = ds.Tables[0].Rows[0]["SocialScience"].ToString();
}
else
{
// Whatever you want to do if no row is found
}
And a simpler sp, which will return a empty table if nothing is found
ALTER PROCEDURE sp_studentresult
(
#id int
)
AS
-- I have removed the extra id column as not sure why you use it
SELECT * from studentresult where id_student=#id
Your SP doesn't return any tabular data in case of a non existing id. Try change it to something like
IF NOT EXISTS (SELECT * FROM student WHERE id=#id_student)
BEGIN
SET #output='Does not EXIST'
END
SELECT * from studentresult where id_student=#id

Categories

Resources