Use stored procedure with parameters in Entity Framework - c#

I'm using Entity Framework 6.1.3 and have used the database-first approach to let it generate the model files and the .EDMX. I also have the following stored procedure on SQL Server 2008 R2, which Entity Framework brought into the EDMX:
CREATE PROCEDURE [dbo].[FindEmployee]
#LastName nvarchar(50),
#employeeID nvarchar(50),
#securityID nvarchar(50)
AS
BEGIN
SET NOCOUNT ON;
select *
from Employee
where
(lastName = dbo.trim(#LastName) AND dbo.trim(#LastName) IS NOT NULL)
OR (employeeID = dbo.trim(#employeeID) AND dbo.trim(#employeeID) IS NOT NULL)
OR (securityID = dbo.trim(#securityID) AND dbo.trim(#securityID) IS NOT NULL)
order by
case when dbo.trim(#LastName) is not null then CONVERT(char(50), lastName) + CONVERT(char(50), firstName)
when dbo.trim(#employeeID) is not null then employeeID
when dbo.trim(#securityID) is not null then securityID
end
END
In a Windows WPF app, I let the user select the column to search on (lastName, employeeID, or securityID) from a combobox. The user provides a search value which will get plugged into that parameter in the call to the stored procedure. The stored procedure then returns a resultset from its SELECT which I'll use to populate a DataGrid.
I'm trying to call the stored procedure in this code; Note that the FindEmployee_Result is an auto-generated class in the EDMX for the stored procedure:
public FindEmployee_Result SearchEmployees(string lastName, string employeeID, string securityID)
{
var results = new FindEmployee_Result();
using (var ctx = new TestSelectionEntities())
{
results = ctx.FindEmployee(lastName,employeeID,securityID);
}
return results;
}
This code blows up with this error:
Cannot implicitly convert type 'System.Data.Entity.Core.Objects.ObjectResult' to 'TestSelection.data.FindEmployee_Result'
What am I missing? Thank you.

The solution is to use a List, as the stored procedure returns a resultset of FindEmployee_Result objects:
public List<FindEmployee_Result> SearchEmployees(string lastName, string employeeID, string securityID)
{
using (var ctx = new TestSelectionEntities())
{
return ctx.FindEmployee(lastName,employeeID,securityID).ToList();
}
}

Related

Strange Behaviour moving from firebird sql version 2.5 to version 4

I have a Windows application written in C# using embedded firebird sql version 2.5.5.26952, which I am re-working it to update to embedded firebird sql version 4.0.0.2496. I have update the fdb file to the new version,and all the tables and sprocs, are there. When run a cmd.Fill() command for a selected statement rows are returned, if I do a update for a row in the table, I get the expected results back fine. but If I do a insert nothing is returned, and no errors are thrown, but the data is added to the database. If I run the sproc from the FireRobin application, the data is inserted, and a row is returned, so I'm at a loss to know why it is not working from my C# application. below is slimmed down version of the code.
The 2.5 version is using FirebirdSql.Data.FirebirdClient.4.10.0.0
The 4.0 version is using FirebirdSql.Data.FirebirdClient.9.0.2
using (var cmd = new FbDataAdapter("PROC_UPSERTPEOPLE", _connection)
{
DataTable data = new DataTable();
cmd.SelectCommand.Parameters.Add("SURNAME", FbDbType.Text).Value = item.Surname;
cmd.SelectCommand.Parameters.Add("FORENAMENAME", FbDbType.Text).Value = item.Forename);
var transaction = _connection.BeginTransaction();
cmd.SelectCommand.CommandType = CommandType.StoredProcedure;
cmd.SelectCommand.Transaction = transaction;
var result = cmd.Fill(data);
transaction.Commit();
}
On a update result contains 1, and data has the expected result, but on a insert result = 0, and data has no rows in.
Any help would be appreciated.
This is the simple version fo the sproc in question
CREATE OR ALTER PROCEDURE PROC_UPSERTPEOPLE_SLIM
(
RECID INTEGER,
SURNAME VARCHAR(100),
FORENAME VARCHAR(100)
)
RETURNS
(
ID INTEGER,
LSURNAME VARCHAR(100),
LFORENAME VARCHAR(100)
)
AS
DECLARE VARIABLE local_id integer;
DECLARE VARIABLE local_surname varchar(100);
DECLARE VARIABLE local_forename varchar(100);
BEGIN
select
ID,
FORENAME,
SURNAME
FROM
APA_PEOPLE
WHERE
(:RECID IS NOT NULL AND ID = :RECID)
OR (:RECID IS NULL
AND FORENAME = :FORENAME
AND SURNAME = :SURNAME)
INTO
:local_id,
:local_forename,
:local_surname;
IF (:local_id IS NULL) then
begin
UPDATE OR INSERT INTO APA_PEOPLE(FORENAME, SURNAME)
VALUES(:FORENAME, :SURNAME)
MATCHING (FORENAME, SURNAME);
end
else
begin
UPDATE APA_PEOPLE SET FORENAME = :FORENAME,
SURNAME = :SURNAME
WHERE ID = :local_id;
end
FOR
SELECT
ID,
SURNAME,
FORENAME
from
APA_PEOPLE
WHERE
(:RECID IS NOT NULL AND ID = :RECID)
OR (:RECID IS NULL
AND FORENAME = :FORENAME
AND SURNAME = :SURNAME)
INTO
:ID,
:LSURNAME,
:LFORENAME
DO
begin
suspend;
end
END;
Update
To answer my own question, being mainly a TSQL developer, DSQL seems strange, change the sproc to the following, which is simpler
CREATE OR ALTER PROCEDURE PROC_UPSERTPEOPLE_SLIM (
RECID integer,
SURNAME varchar(100),
FORENAME varchar(100)
)
RETURNS (ID integer)SQL SECURITY INVOKER
AS
BEGIN
UPDATE OR INSERT INTO APA_PEOPLE(FORENAME, SURNAME)
VALUES(:FORENAME, :SURNAME)
MATCHING (FORENAME, SURNAME)
RETURNING ID INTO :ID;
END;
but also had to change the way it was called, to use
EXECUTE PROCEDURE PROC_UPSERTPEOPLE_SLIM(#RECID, #SURNAME, #FORENAME)
This does seem counter intuitive, I had assumed a stored procedure was a stored procedure, and there are not two different flavors. Oh well it works now, so move on to getting the rest of the app to work.

Insert using DataContext and getting ID CSLA C#

How can I retrieve the ID during an insert in C# using CSLA? The stored procedure does an insert into the database table and then has a SELECT #Id (which is set with the SCOPE_IDENTITY()) after the insert.
This is the code to insert in C#:
using (var mgr = ContextManager<PersonDataContext>.GetManager("TestDB"))
{
var results = mgr.DataContext.up_StoredProcToInsert(
"David",
30,
);
}
try below example based on CRUD Operations using Stored Procedure in Entity Framework:
SP:
CREATE PROCEDURE SP_Ins_Test
#name nchar(10)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO dbo.test(name)
SELECT #name
SELECT SCOPE_IDENTITY() AS ResultId
END
GO
C# code:
DemoDB_JRDevEntities db = new DemoDB_JRDevEntities();
SP_Ins_Test_Result r=db.SP_Ins_Test("Raj").First();
string id= r.ResultId.ToString();
Although the sample doesn't use a stored procedure, relying on EF to do the work itself, you can look at the EF data access layer in the ProjectTracker sample to see how an insert operation is implemented:
https://github.com/MarimerLLC/csla/blob/master/Samples/ProjectTracker/ProjectTracker.DalEf/ProjectDal.cs#L82
public void Insert(ProjectDto item)
{
using (var ctx = ObjectContextManager<PTrackerEntities>.GetManager("PTrackerEntities"))
{
var newItem = new Project
{
Name = item.Name,
Description = item.Description,
Started = item.Started,
Ended = item.Ended
};
ctx.ObjectContext.AddToProjects(newItem);
ctx.ObjectContext.SaveChanges();
item.Id = newItem.Id;
item.LastChanged = newItem.LastChanged;
}
}

How to use Table valued parameter in Stored Procedure and then call it in MVC C# Visual studio?

I have created user defined datatype which is of type table as:
Create type Employeetable as Table
(
FirstName varchar(50),
LastName varchar(50),
States varchar(50),
City varchar(50),
AddressLine1 varchar(100),
AddressLine2 varchar(100)
)
But now I am consfused as to how should I use it in stored procedure , doing a basic CRUD operation here . THis is how i have used Create Procedure:
Create Procedure InsertEmployees
#employeetable Employeetable Readonly
as
begin
Insert into Testing.Employees
select * from #employeetable
end
Also I don't know how to use it in MVC C# in visual studio because when I added stored procedure it showed this error:
Error 6005: The function 'InsertEmployees' has a parameter 'employeetable' at parameter index 0 that has a data type 'table type' which is currently not supported for the target Entity Framework version. The function was excluded
Also in controller how should I proceed with the code , in normal stored procedure I would write these in [HttpPost]:
public ActionResult AddProduct([Table name] [table object])
{
ObjectParameter objParam = new ObjectParameter("productID", typeof(int));
int result =
db.usp_SAVE_tbl_Products_PG_ADODotNetDemoCode(objProduct.ProductID,
objProduct.ProductName, objProduct.Rate, objProduct.Quantity, objParam);
this.db.SaveChanges();
int resultVal = Convert.ToInt32(objParam.Value);
return RedirectToAction("ListProducts");
}
Kindly help with this thanks

Retrieve table data from stored procedure using entity framework

I'm using Entity Framework v6. I have a stored procedure as shown below
CREATE PROCEDURE [dbo].[GetCountryList]
(
#CustomerName VARCHAR(MAX),
#SearchCriteria VARCHAR(MAX)
)
AS
BEGIN
SET NOCOUNT ON
SELECT CountryID, CountryName FROM dbo.Table1
WHERE CustomerName = #CustomerName AND CountryName = #SearchCriteria
END
Now I have a model class
public class CountryName
{
public int CountryId { get; set; }
public string CountryName { get; set; }
}
So I want to get the result of the SELECT query in a List<CountryName> type
List<CountryName> countryList = null;
using (DbEntities dbContext = new DbEntities())
{
countryList = //my code to collect the result
}
Well, I could have run a LINQ to SQL directly on the table but unfortunately my requirement in to get the data from stored procedure. So, how can I do it?
You need to Import the stored procedure as a Function. Right-click on the workspace area of your Entity model and choose Add -> Function Import.
In the Add Function Import dialog, enter the name you want your stored procedure to be referred to in your model for example GetCountryListSP, choose your procedure from the drop down list, and choose the return value of the procedure to be Entities and choose CountryName from the drop down list.
Then in the code:
var result = db.GetCountryListSP();//Send parameters too
With this approach you prevent returning -1 of the stored procedure. Please check this post for more details about stored procedure problem with Entity Framework.
You can do it without importing. Something like that:
var countryList = dbContext.Database.SqlQuery<CountryName>("[GetCountryList]").ToList();
EntityFramework sometimes won't recognize or import SPs ))) So, that's why I saving my hours with this snippet.

Stored procedure/query two variable comparison

I have created a stored procedure for SQL Server 2014.
There are two parameters: Name which is a user name and Hash which is password md5 hash. I check in the database if the md5 hashes are equal (first hash is from the program and the second one is already stored in the database).
If I just run a query (not a stored procedure) in the database (or in program using commandType.Text) - everything works and the user is being selected, but when I run the exact thing but using stored procedures, the SqlReader in C# has no elements returned, which most likely means that the conditions during those variable comparison were not met.
Maybe I am doing something wrong?
I also have about 10 other stored procedures for reading or/and writing to the database, everything works except this one.
Here is the procedure:
CREATE PROCEDURE GetHash
#Name nvarchar(50),
#Hash nvarchar(200)
AS
BEGIN
SET NOCOUNT ON;
SELECT Orders.orderId, Employee.name, Employee.surname
FROM Orders
LEFT JOIN Employee ON Orders.orderId = Employee.id
WHERE batchName = '#Name' AND productCode = '#Hash'
END
GO
Code part:
public Boolean VerifyPassword(string name, string password)
{
var paramsList = new List<SqlParameter> { new SqlParameter("#Name", name), new SqlParameter("#Hash", GetMd5Hash(password)) };
const string ProcedureName = "GetHash";
var ActiveUser = new DBController().GetFromDatabase(ProcedureName, "Login", "EJL15_DB", paramsList).ToList();
return ActiveUser.Count > 0;
}
And from Database Controller
private void SetCommandProperties(string procedureName, IEnumerable<SqlParameter> paramsList)
{
this.sqlCommand.CommandText = procedureName;
this.sqlCommand.CommandType = CommandType.StoredProcedure;
foreach (var curParam in paramsList)
this.sqlCommand.Parameters.Add(curParam);
this.sqlCommand.CommandTimeout = 15;
}
You don't need to quote the parameters in the stored procedure. Do this instead:
CREATE PROCEDURE GetHash
#Name nvarchar(50),
#Hash nvarchar(200)
AS
BEGIN
SET NOCOUNT ON;
SELECT Orders.orderId,
Employee.name,
Employee.surname
FROM Orders
LEFT JOIN Employee
ON Orders.orderId=Employee.id
WHERE batchName = #Name
AND productCode = #Hash
END
I just wonder, obviously your #Hash parameter passed to the stored
procedure is a user's password. But for some reason your WHERE clause
in the procedure goes like that:
"WHERE batchName='#Name' AND productCode='#Hash'"
Is there a chance your condition is incorrect? I guess it should be something like: Employee.password = #Hash
You should not put '' around your variables. Otherwise your comparison is totally wrong.

Categories

Resources