I am using EF Core 1.0 in an ASP.NET Core App. Can you please point me to the proper way of executing stored procedures? The old method with ObjectParameters and ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction is not working.
Support for stored procedures in EF Core 1.0 is resolved now, this also supports the mapping of multiple result-sets.
Check here for the fix details
And you can call it like this in c#
var userType = dbContext.Set().FromSql("dbo.SomeSproc #Id = {0}, #Name = {1}", 45, "Ada");
Stored procedure support is not yet (as of 7.0.0-beta3) implemented in EF7. You can track the progress of this feature using issue #245.
For now, you can do it the old fashioned way using ADO.NET.
var connection = (SqlConnection)context.Database.AsSqlServer().Connection.DbConnection;
var command = connection.CreateCommand();
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "MySproc";
command.Parameters.AddWithValue("#MyParameter", 42);
command.ExecuteNonQuery();
To execute the stored procedures, use FromSql method which executes RAW SQL queries
e.g.
var products= context.Products
.FromSql("EXECUTE dbo.GetProducts")
.ToList();
To use with parameters
var productCategory= "Electronics";
var product = context.Products
.FromSql("EXECUTE dbo.GetProductByCategory {0}", productCategory)
.ToList();
or
var productCategory= new SqlParameter("productCategory", "Electronics");
var product = context.Product
.FromSql("EXECUTE dbo.GetProductByName #productCategory", productCategory)
.ToList();
There are certain limitations to execute RAW SQL queries or stored procedures. You can’t use it for INSERT/UPDATE/DELETE. if you want to execute INSERT, UPDATE, DELETE queries, use the ExecuteSqlCommand
var categoryName = "Electronics";
dataContext.Database
.ExecuteSqlCommand("dbo.InsertCategory #p0", categoryName);
The support for stored procedure in EF Core is similar to the earlier versions of EF Code first.
You need to create your DbContext class by inherting the DbContext class from EF. The stored procedures are executing using the DbContext.
First step is to write a method that create a DbCommand from the DbContext.
public static DbCommand LoadStoredProc(
this DbContext context, string storedProcName)
{
var cmd = context.Database.GetDbConnection().CreateCommand();
cmd.CommandText = storedProcName;
cmd.CommandType = System.Data.CommandType.StoredProcedure;
return cmd;
}
To pass parameters to the stored procedure use the following method.
public static DbCommand WithSqlParam(
this DbCommand cmd, string paramName, object paramValue)
{
if (string.IsNullOrEmpty(cmd.CommandText))
throw new InvalidOperationException(
"Call LoadStoredProc before using this method");
var param = cmd.CreateParameter();
param.ParameterName = paramName;
param.Value = paramValue;
cmd.Parameters.Add(param);
return cmd;
}
Finally for mapping the result into a list of custom objects use the MapToList method.
private static List<T> MapToList<T>(this DbDataReader dr)
{
var objList = new List<T>();
var props = typeof(T).GetRuntimeProperties();
var colMapping = dr.GetColumnSchema()
.Where(x => props.Any(y => y.Name.ToLower() == x.ColumnName.ToLower()))
.ToDictionary(key => key.ColumnName.ToLower());
if (dr.HasRows)
{
while (dr.Read())
{
T obj = Activator.CreateInstance<T>();
foreach (var prop in props)
{
var val =
dr.GetValue(colMapping[prop.Name.ToLower()].ColumnOrdinal.Value);
prop.SetValue(obj, val == DBNull.Value ? null : val);
}
objList.Add(obj);
}
}
return objList;
}
Now we’re ready for execute the stored procedute with the ExecuteStoredProc method and maps it to the a List whose type that’s passed in as T.
public static async Task<List<T>> ExecuteStoredProc<T>(this DbCommand command)
{
using (command)
{
if (command.Connection.State == System.Data.ConnectionState.Closed)
command.Connection.Open();
try
{
using (var reader = await command.ExecuteReaderAsync())
{
return reader.MapToList<T>();
}
}
catch(Exception e)
{
throw (e);
}
finally
{
command.Connection.Close();
}
}
}
For example, to execute a stored procedure called “StoredProcedureName” with two parameters called “firstparamname” and “secondparamname” this is the implementation.
List<MyType> myTypeList = new List<MyType>();
using(var context = new MyDbContext())
{
myTypeList = context.LoadStoredProc("StoredProcedureName")
.WithSqlParam("firstparamname", firstParamValue)
.WithSqlParam("secondparamname", secondParamValue).
.ExecureStoredProc<MyType>();
}
I tried all the other solutions but didn't worked for me. But I came to a proper solution and it may be helpful for someone here.
To call a stored procedure and get the result into a list of model in EF Core, we have to follow 3 steps.
Step 1.
You need to add a new class just like your entity class. Which should have properties with all the columns in your SP. For example if your SP is returning two columns called Id and Name then your new class should be something like
public class MySPModel
{
public int Id {get; set;}
public string Name {get; set;}
}
Step 2.
Then you have to add one DbQuery property into your DBContext class for your SP.
public partial class Sonar_Health_AppointmentsContext : DbContext
{
public virtual DbSet<Booking> Booking { get; set; } // your existing DbSets
...
public virtual DbQuery<MySPModel> MySP { get; set; } // your new DbQuery
...
}
Step 3.
Now you will be able to call and get the result from your SP from your DBContext.
var result = await _context.Query<MySPModel>().AsNoTracking().FromSql(string.Format("EXEC {0} {1}", functionName, parameter)).ToListAsync();
I am using a generic UnitOfWork & Repository. So my function to execute the SP is
/// <summary>
/// Execute function. Be extra care when using this function as there is a risk for SQL injection
/// </summary>
public async Task<IEnumerable<T>> ExecuteFuntion<T>(string functionName, string parameter) where T : class
{
return await _context.Query<T>().AsNoTracking().FromSql(string.Format("EXEC {0} {1}", functionName, parameter)).ToListAsync();
}
Hope it will be helpful for someone !!!
"(SqlConnection)context"
-- This type-casting no longer works. You can do: "SqlConnection context;
".AsSqlServer()"
-- Does not Exist.
"command.ExecuteNonQuery();"
-- Does not return results. reader=command.ExecuteReader() does work.
With dt.load(reader)... then you have to switch the framework out of 5.0 and back to 4.51, as 5.0 does not support datatables/datasets, yet. Note: This is VS2015 RC.
Currently EF 7 or EF Core does not support the old method of importing Stored procedures in designer and calling them directly. You can have a look at the roadmap to see what is going to be supported in the future:
EF core roadmap.
So for now it is better to use SqlConnection to call stored procedures or any raw query, since you do not need the entire EF for this job. Here are two examples:
Call stored procedure that return single value. String in this case.
CREATE PROCEDURE [dbo].[Test]
#UserName nvarchar(50)
AS
BEGIN
SELECT 'Name is: '+#UserName;
END
Call stored procedure that return a list.
CREATE PROCEDURE [dbo].[TestList]
AS
BEGIN
SELECT [UserName], [Id] FROM [dbo].[AspNetUsers]
END
To call these stored procedure it is better to create static class that holds all of these functions, for example, I called it DataAccess class, as follows:
public static class DataAccess
{
private static string connectionString = ""; //Your connection string
public static string Test(String userName)
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
// 1. create a command object identifying the stored procedure
SqlCommand cmd = new SqlCommand("dbo.Test", conn);
// 2. set the command object so it knows to execute a stored procedure
cmd.CommandType = CommandType.StoredProcedure;
// 3. add parameter to command, which will be passed to the stored procedure
cmd.Parameters.Add(new SqlParameter("#UserName", userName));
// execute the command
using (var rdr = cmd.ExecuteReader())
{
if (rdr.Read())
{
return rdr[0].ToString();
}
else
{
return null;
}
}
}
}
public static IList<Users> TestList()
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
// 1. create a command object identifying the stored procedure
SqlCommand cmd = new SqlCommand("dbo.TestList", conn);
// 2. set the command object so it knows to execute a stored procedure
cmd.CommandType = CommandType.StoredProcedure;
// execute the command
using (var rdr = cmd.ExecuteReader())
{
IList<Users> result = new List<Users>();
//3. Loop through rows
while (rdr.Read())
{
//Get each column
result.Add(new Users() { UserName = (string)rdr.GetString(0), Id = rdr.GetString(1) });
}
return result;
}
}
}
}
And Users class is like this:
public class Users
{
public string UserName { set; get; }
public string Id { set; get; }
}
By the way you do not need to worry about the performance of opening and closing a connection for every request to sql as the asp.net is taking care of managing these for you.
And I hope this was helpful.
I had a lot of trouble with the ExecuteSqlCommand and ExecuteSqlCommandAsync, IN parameters were easy, but OUT parameters were very difficult.
I had to revert to using DbCommand like so -
DbCommand cmd = _context.Database.GetDbConnection().CreateCommand();
cmd.CommandText = "dbo.sp_DoSomething";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#firstName", SqlDbType.VarChar) { Value = "Steve" });
cmd.Parameters.Add(new SqlParameter("#lastName", SqlDbType.VarChar) { Value = "Smith" });
cmd.Parameters.Add(new SqlParameter("#id", SqlDbType.BigInt) { Direction = ParameterDirection.Output });
I wrote more about it in this post.
Since it is agreed in my team that we are going to use generic UnitOfWork pattern, I have taken a bit of everyone's solutions when creating mine.
I am posting a bit of UnitOfWork code as well so you can get a grasp of why I needed to implement it like so.
public interface IUnitOfWork : IDisposable
{
DbContext Context { get; }
Task<List<T>> ExecuteStoredProc<T>(string storedProcName, Dictionary<string, object> procParams) where T : class;
}
Interface implementation:
public class UnitOfWork : IUnitOfWork
{
public DbContext Context { get; private set; }
/// <summary>
/// Execute procedure from database using it's name and params that is protected from the SQL injection attacks.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="storedProcName">Name of the procedure that should be executed.</param>
/// <param name="procParams">Dictionary of params that procedure takes. </param>
/// <returns>List of objects that are mapped in T type, returned by procedure.</returns>
public async Task<List<T>> ExecuteStoredProc<T>(string storedProcName, Dictionary<string, object> procParams) where T : class
{
DbConnection conn = Context.Database.GetDbConnection();
try
{
if(conn.State != ConnectionState.Open)
await conn.OpenAsync();
await using (DbCommand command = conn.CreateCommand())
{
command.CommandText = storedProcName;
command.CommandType = CommandType.StoredProcedure;
foreach (KeyValuePair<string, object> procParam in procParams)
{
DbParameter param = command.CreateParameter();
param.ParameterName = procParam.Key;
param.Value = procParam.Value;
command.Parameters.Add(param);
}
DbDataReader reader = await command.ExecuteReaderAsync();
List<T> objList = new List<T>();
IEnumerable<PropertyInfo> props = typeof(T).GetRuntimeProperties();
Dictionary<string, DbColumn> colMapping = reader.GetColumnSchema()
.Where(x => props.Any(y => y.Name.ToLower() == x.ColumnName.ToLower()))
.ToDictionary(key => key.ColumnName.ToLower());
if (reader.HasRows)
{
while (await reader.ReadAsync())
{
T obj = Activator.CreateInstance<T>();
foreach (PropertyInfo prop in props)
{
object val =
reader.GetValue(colMapping[prop.Name.ToLower()].ColumnOrdinal.Value);
prop.SetValue(obj, val == DBNull.Value ? null : val);
}
objList.Add(obj);
}
}
reader.Dispose();
return objList;
}
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e.Message, e.InnerException);
}
finally
{
conn.Close();
}
return null; // default state
}
Example usage is like so:
public class MyService : IMyService
{
private readonly IUnitOfWork _uow;
public MyService(IUnitOfWork uow)
{
_uow = uow;
}
public async Task<List<TreeViewModel>> GetTreeOptions()
{
var procParams = new Dictionary<string, object>()
{
{"#Id", 2}
};
var result = await _uow.ExecuteStoredProc<TreeViewModel>("FetchTreeProcedure", procParams);
return result;
}
}
I found this extention very usefull: StoredProcedureEFCore
Then the usage is like this
List<Model> rows = null;
ctx.LoadStoredProc("dbo.ListAll")
.AddParam("limit", 300L)
.AddParam("limitOut", out IOutParam<long> limitOut)
.Exec(r => rows = r.ToList<Model>());
long limitOutValue = limitOut.Value;
ctx.LoadStoredProc("dbo.ReturnBoolean")
.AddParam("boolean_to_return", true)
.ReturnValue(out IOutParam<bool> retParam)
.ExecNonQuery();
bool b = retParam.Value;
ctx.LoadStoredProc("dbo.ListAll")
.AddParam("limit", 1L)
.ExecScalar(out long l);
Using MySQL connector and Entity Framework Core 2.0
My issue was that I was getting an exception like fx. Ex.Message = "The required column 'body' was not present in the results of a 'FromSql' operation.". So, in order to fetch rows via a stored procedure in this manner, you must return all columns for that entity type which the DBSet is associated with, even if you don't need to access all of it for your current request.
var result = _context.DBSetName.FromSql($"call storedProcedureName()").ToList();
OR with parameters
var result = _context.DBSetName.FromSql($"call storedProcedureName({optionalParam1})").ToList();
I'm using Entity Framework Core with my ASP.Net Core 3.x WebAPI. I wanted one of my end points just to execute a particular Stored Procedure, and this is the code I needed:
namespace MikesBank.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ResetController : ControllerBase
{
private readonly MikesBankContext _context;
public ResetController(MikesBankContext context)
{
_context = context;
}
[HttpGet]
public async Task<ActionResult> Get()
{
try
{
using (DbConnection conn = _context.Database.GetDbConnection())
{
if (conn.State != System.Data.ConnectionState.Open)
conn.Open();
var cmd = conn.CreateCommand();
cmd.CommandText = "Reset_Data";
await cmd.ExecuteNonQueryAsync();
}
return new OkObjectResult(1);
}
catch (Exception ex)
{
return new BadRequestObjectResult(ex.Message);
}
}
}
}
Notice how I need to get my DbContext which has been injected, but I also need to Open() this connection.
Create the special class according the fields in your Select query of your stored procedure.
For example I will call this class ResulData
Add to context of you EF
modelBuilder.Entity<ResultData>(e =>
{
e.HasNoKey();
});
And this a sample function to get data using the store procedure
public async Task<IEnumerable<ResultData>> GetDetailsData(int id, string name)
{
var pId = new SqlParameter("#Id", id);
var pName = new SqlParameter("#Name", name);
return await _context.Set<ResultData>()
.FromSqlRaw("Execute sp_GetDeailsData #Id #Name", parameters: new[] { pId, pName })
.ToArrayAsync();
}
I used StoredProcedureEFCore nuget package by https://github.com/verdie-g/StoredProcedureEFCore,EnterpriseLibrary.Data.NetCore,EFCor.SqlServer,EFCore.Tools
I tried DbFirst approach with {Repository pattern}.. i think so
startup.cs
ConfigureServices(IServiceCollection services){
services.AddDbContext<AppDbContext>(opt => opt
.UseSqlServer(Configuration.GetConnectionString("SampleConnectionString")));
services.AddScoped<ISomeDAL, SomeDAL>();
}
public class AppDbContext : DbContext{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{}
}
ISomeDAl Interface has {GetPropertiesResponse GetAllPropertiesByCity(int CityId);}
public class SomeDAL : ISomeDAL
{
private readonly AppDbContext context;
public SomeDAL(AppDbContext context)
{
this.context = context;
}
public GetPropertiesResponse GetAllPropertiesByCity(int CityId)
{
//Create Required Objects for response
//wont support ref Objects through params
context.LoadStoredProc(SQL_STATEMENT)
.AddParam("CityID", CityId).Exec( r =>
{
while (r.Read())
{
ORMapping<GenericRespStatus> orm = new ORMapping<GenericRespStatus>();
orm.AssignObject(r, _Status);
}
if (r.NextResult())
{
while (r.Read())
{
Property = new Property();
ORMapping<Property> orm = new ORMapping<Property>();
orm.AssignObject(r, Property);
_propertyDetailsResult.Add(Property);
}
}
});
return new GetPropertiesResponse{Status=_Status,PropertyDetails=_propertyDetailsResult};
}
}
public class GetPropertiesResponse
{
public GenericRespStatus Status;
public List<Property> PropertyDetails;
public GetPropertiesResponse()
{
PropertyDetails = new List<Property>();
}
}
public class GenericRespStatus
{
public int ResCode { get; set; }
public string ResMsg { get; set; }
}
internal class ORMapping<T>
{
public void AssignObject(IDataReader record, T myClass)
{
PropertyInfo[] propertyInfos = typeof(T).GetProperties();
for (int i = 0; i < record.FieldCount; i++)
{
if (propertyInfos.Any(obj => obj.Name == record.GetName(i))) //&& record.GetValue(i) != DBNull.Value
{
propertyInfos.Single(obj => obj.Name == record.GetName(i)).SetValue(myClass, Convert.ChangeType(record.GetValue(i), record.GetFieldType(i)));
}
}
}
}
It's embarrassing how lacking the docs are on this. 😩
It took me a lot of hit and trial to figure this out 😪, so I wanted to document 📝 it here so someone else doesn't have to spend time figuring this out. I'm using Entity Framework Core Version 6.0.10.
Summary
There are 2 kinds of Stored Procedures that return result. And the approach to call them and get result is different from each other.
SPs that return table-based output.
SPs that return output in the output parameters.
SPs that return table based output
If your SP looks like this:
CREATE PROCEDURE dbo.MyTestSPToGetShopType #ShopId AS VARCHAR(25)
AS
SELECT ShopId, ShopType
FROM Shop
WHERE SHOPID = #ShopId
👇
Step 1:
Create a class based on your output
public class MyTestSpResult
{
public string ShopId { get; set; }
public string ShopType { get; set; }
}
Step 2:
Register this in your DbContext's protected override void OnModelCreating(ModelBuilder builder) method:
builder.Entity<MyTestSpResult>(e => e.HasNoKey());
Step 3:
Call the SP from the code, and get the result:
var myTestSpResult = await _dbContext.Set<MyTestSpResult>()
.FromSqlInterpolated($"EXEC dbo.MyTestSPToGetShopType #ShopId = \"A03\"")
.ToArrayAsync();
var myShopType = myTestSpResult[0].ShopType;
Alternate Way
Steps 1 and 2 are same as above.
Step 3:
Register the class from Step 1 in your DbContext:
public virtual DbSet<MyTestSpResult> MyTestSpResult { get; set; }
Step 4:
Call the SP from the code, and get the result:
var mySPResult = await _dbContext.MyTestSpResult
.FromSqlInterpolated($"EXEC dbo.MyTestSPToGetShopType #ShopId = \"A03\"")
.ToArrayAsync();
var myShopType = mySPResult[0].ShopType;
SPs that return output in the output parameters
If your SP looks like this:
CREATE PROCEDURE dbo.MyOtherTestSPToGetShopType
(
#ShopId VARCHAR(25)
,#ShopType VARCHAR(25) OUTPUT
)
AS
SELECT #ShopType = ShopType
FROM Shop
WHERE SHOPID = #ShopId
👇
Step 1:
Create the SQL parameters:
var shopId = new SqlParameter()
{
ParameterName = "#ShopId",
Value = "A03",
Direction = System.Data.ParameterDirection.Input,
SqlDbType = System.Data.SqlDbType.VarChar,
Size = 25
};
var shopType = new SqlParameter()
{
ParameterName = "#ShopType",
Direction = System.Data.ParameterDirection.Output,
SqlDbType = System.Data.SqlDbType.VarChar,
Size = 25
};
Step 2:
Call the SP from code using those parameters, and get the result:
await _dbContext.Database
.ExecuteSqlInterpolatedAsync($"EXEC dbo.MyOtherTestSPToGetShopType #ShopId = {shopId}, #ShopType = {shopType} OUT");
var myShopType = shopType.Value as string;
If you are executing a stored procedure from Informix using EntityFrameworkCore you need to include the command EXECUTE PROCEDURE
var spresult = _informixContext.procdata.FromSql("EXECUTE PROCEDURE dummyproc ({0},{1},{2})", parameters: new[] { p0, p1,p2 }).ToList();
Nothing have to do... when you are creating dbcontext for code first approach initialize
namespace below the fluent API area make list of sp and use it another place where you want.
public partial class JobScheduleSmsEntities : DbContext
{
public JobScheduleSmsEntities()
: base("name=JobScheduleSmsEntities")
{
Database.SetInitializer<JobScheduleSmsEntities>(new CreateDatabaseIfNotExists<JobScheduleSmsEntities>());
}
public virtual DbSet<Customer> Customers { get; set; }
public virtual DbSet<ReachargeDetail> ReachargeDetails { get; set; }
public virtual DbSet<RoleMaster> RoleMasters { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//modelBuilder.Types().Configure(t => t.MapToStoredProcedures());
//modelBuilder.Entity<RoleMaster>()
// .HasMany(e => e.Customers)
// .WithRequired(e => e.RoleMaster)
// .HasForeignKey(e => e.RoleID)
// .WillCascadeOnDelete(false);
}
public virtual List<Sp_CustomerDetails02> Sp_CustomerDetails()
{
//return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<Sp_CustomerDetails02>("Sp_CustomerDetails");
// this.Database.SqlQuery<Sp_CustomerDetails02>("Sp_CustomerDetails");
using (JobScheduleSmsEntities db = new JobScheduleSmsEntities())
{
return db.Database.SqlQuery<Sp_CustomerDetails02>("Sp_CustomerDetails").ToList();
}
}
}
}
public partial class Sp_CustomerDetails02
{
public long? ID { get; set; }
public string Name { get; set; }
public string CustomerID { get; set; }
public long? CustID { get; set; }
public long? Customer_ID { get; set; }
public decimal? Amount { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public int? CountDay { get; set; }
public int? EndDateCountDay { get; set; }
public DateTime? RenewDate { get; set; }
public bool? IsSMS { get; set; }
public bool? IsActive { get; set; }
public string Contact { get; set; }
}
I'm using Entity Framework Core. The support for stored procedures and adhoc queries doesn't feel as fluid as it does in Framework.
Here are some examples for future reference:
Populate a list of entities from the results of a stored procedure:
The [dbo].[GetUnarchivedJobs] stored procedure returns a list of records that matches the Job entity.
We can use the FromSqlInterpolated() method on the Jobs property to call the stored procedure and have a list of Job returned.
NoTracking() is used to speed up the performance, and in this case we wont be updating the entities.
using Microsoft.EntityFrameworkCore;
public class DbContext : Microsoft.EntityFrameworkCore.DbContext
{
protected DbSet<Job> Jobs { get; set; }
// Populate a list of entities from the results of a stored procedure
public Task<List<Job>> GetUnarchivedJobs(int maxQty, CancellationToken cancellationToken) =>
Jobs.FromSqlInterpolated($"EXEC [dbo].[GetUnarchivedJobs] #MaxQty = {maxQty}")
.AsNoTracking()
.ToListAsync(cancellationToken)
;
public DbContext(DbContextOptions<DbContext> options) : base(options) { }
}
Send an array of integers to a stored procedure:
The [dbo].[SetJobListArchiveFlags] stored procedure has a single parameter of type integer_list_tbltype.
We need to create a DataTable to match the integer_list_tbltype type which has a single column named n.
The int values need to be added to the DataTable.
A SqlParameter is used to pass the populated DataTable to the stored procedure.
Because we are not populating any entities, we need to use methods on the Database property to call the stored procedure.
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using System.Data;
public class DbContext : Microsoft.EntityFrameworkCore.DbContext
{
// Send an array of integers to a stored procedure
public async Task<int> MarkJobsAsArchived(IEnumerable<int> jobIds, CancellationToken cancellationToken)
{
// This DataTable matches the `integer_list_tbltype` db type
var table = new DataTable();
table.Columns.Add("n", typeof(int));
foreach (var id in jobIds) table.Rows.Add(id);
var parameter = new SqlParameter("#jobIds", SqlDbType.Structured);
parameter.Value = table;
parameter.TypeName = "integer_list_tbltype";
var rowsUpdatedCount = await Database.ExecuteSqlRawAsync("EXEC [dbo].[SetJobListArchiveFlags] #jobIds", new[] { parameter }, cancellationToken);
return rowsUpdatedCount;
}
}
From EF core 3.0 onwards, we can also use the following commands:
dbContext.Database.ExecuteSqlInterpolated():
var name = "Ramin";
var outArticleCount = new SqlParameter(
"#outArticleCount",
SqlDbType.Int) { Direction = ParameterDirection.Output };
dbContext.Database.ExecuteSqlInterpolated(
$"exec dbo.MySp {name}, {outputArticleCount} out");
dbContext.Database.ExecuteSqlInterpolatedAsync():
dbContext.Database.ExecuteSqlRaw():
SqlParameter[] parameters =
{
new SqlParameter("#name", SqlDbType.Varchar { Direction = ParameterDirection.Input, Value = "Ramin" },
new SqlParameter("#outArticleCount", SqlDbType.Int { Direction = ParameterDirection.Output }
}
dbContext.Database.ExecuteSqlRaw("exec dbo.MySp #name, #outArticleCount OUTPUT", parameters);
dbContext.Database.ExecuteSqlRawAsync()
Raw and Interpolated versions of above methods are equal but Interpolated versions are safe against SQL Injection attacks (read more here and here).
We should create a property with DbQuery not DbSet in the model for the db context like below...
public class MyContextContext : DbContext
{
public virtual DbQuery<CheckoutInvoiceModel> CheckoutInvoice { get; set; }
}
After than a method that can be used to return result
public async Task<IEnumerable<CheckoutInvoiceModel>> GetLabReceiptByReceiptNo(string labReceiptNo)
{
var listing = new List<CheckoutInvoiceModel>();
try
{
var sqlCommand = $#"[dbo].[Checkout_GetLabReceiptByReceiptNo] {labReceiptNo}";
listing = await db.Set<CheckoutInvoiceModel>().FromSqlRaw(sqlCommand).ToListAsync();
}
catch (Exception ex)
{
return null;
}
return listing;
}
From above example, we can use any one option you like.
Hope this helpful for you!
I am trying to host an external facing WCF service on Azure within a worker role.
I have a solution working very nice locally, but when I try to publish it to Azure it goes into an initializing/busy/stopped loop.
The information I've found around the internet says different things:
http://www.theworkflowelement.com/2011/01/worker-role-service-hosting-faq.html (impossible)
http://code.msdn.microsoft.com/WCF-Azure-Worker-Role-on-b394df49 (possible with hack)
Other sources say it's possible, but I don't have the rep to post more than two links.
The last one hangs on busy when I try to publish it.
Anyone know how to do this, or if it really is impossible? It would be very nice to host it in a worker role, so I don't have to use the svc and web.config mess that a web role entails.
This is the code I am using:
[ServiceContract(Namespace = "")]
public interface IMyService
{
[OperationContract]
[WebGet]
string Echo(string s);
}
public class MyService : IMyService
{
public string Echo(string s)
{
return "hey " + s;
}
}
public class TestPasswordValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
}
}
private static void StartService()
{
var endpoint = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["HttpsEndpoint"];
var uri = new Uri(endpoint.Protocol + "://" + endpoint.IPEndpoint + "/myservice");
var host = new ServiceHost(typeof(MyService), uri);
host.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
host.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new TestPasswordValidator();
var mexBehavior = new ServiceMetadataBehavior();
mexBehavior.HttpsGetEnabled = true;
mexBehavior.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(mexBehavior);
var soapBinding = new WSHttpBinding(SecurityMode.TransportWithMessageCredential);
soapBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
host.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName, MetadataExchangeBindings.CreateMexHttpsBinding(), "mex");
host.AddServiceEndpoint(typeof(IMyService), soapBinding, "Soap");
var restBinding = new WebHttpBinding(WebHttpSecurityMode.Transport);
restBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
var restEndpoint = host.AddServiceEndpoint(typeof(IMyService), restBinding, "");
restEndpoint.Behaviors.Add(new WebHttpBehavior { HelpEnabled = true, DefaultOutgoingResponseFormat = WebMessageFormat.Json, AutomaticFormatSelectionEnabled = true, DefaultBodyStyle = WebMessageBodyStyle.WrappedRequest });
host.Open();
}
public override void Run()
{
StartService();
while (true)
{
Thread.Sleep(10000);
}
}
public override bool OnStart()
{
// Set the maximum number of concurrent connections
ServicePointManager.DefaultConnectionLimit = 12;
// For information on handling configuration changes
// see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.
return base.OnStart();
}
I figured out why this was happening. Worker roles need to run in elevated permissions to open HTTP ports. This setting however, is not available in the role settings gui. The setting the gui shows, which I thought controlled the permissions, is Full trust/Partial trust. I guess I have no idea what that does.
The correct setting is in the ServiceDefinition.csdef file, under WorkerRole.
<Runtime executionContext="elevated" />