Cannot execute Raw Sql in .Net COre - .net-core

I am using Core 2.0 using entity framework.
I have successfully generated context using scaffold DBContext.
I have DBSet for table EMployee.
I need to execute SToredProcedure which will give list of employee.
I cannot see .FromSql nor.ExecuteCommand option.
I have added EntityFrameworkCore.SqlServer(2.0.1),EntityFrameworkCore.SqlServer.Design(1.1.5),Microsoft.VisualStudio.Web.CodeGeneration.Design(2.0.2) and EntityFrameworkCore.Tools(2.0.1) but to no awail.
Please guide for mentioned concerns.

If you want to execute row SQL using EF Core, try the following.
var employees = context.Employees
.FromSql("SELECT * FROM dbo.Employees")
// If you want to execute a stored procedure, then below
// .FromSql("EXECUTE {SP_NAME}")
.ToList();
But note, there are certain limitations present as described here:
https://learn.microsoft.com/en-us/ef/core/querying/raw-sql#limitations

This is the only way to execute Raw SQL in .NET at the moment:
var conn = _context.Database.GetDbConnection();
try
{
await conn.OpenAsync();
using (var command = conn.CreateCommand())
{
command.CommandText = "SELECT * From Table1 WHERE sender = #sender";
DbParameter sender = command.CreateParameter();
sender.ParameterName = "sender";
sender.Value = "Value";
command.Parameters.Add(sender);
DbDataReader reader = await command.ExecuteReaderAsync();
if (reader.HasRows)
{
while (await reader.ReadAsync())
{
int SubscriptionID = reader.GetInt32(0);
}
}
reader.Dispose();
}
}
finally { conn.Close(); }
You can use it for stored procedures as well.

Related

TransactionScope: nested transactions with different database connections (SQL Server & Postgresql)

I am writing an SDK method with transaction using NpgsqlConnection for others to use.
When they were calling my method, they used SqlConnection with another transaction to wrap their DB stuff and my SDK's DB stuff.
If I set my SDK method without a transaction, the outer code was fine and my SDK method could be rolled back. (Which was odd too. Still figuring out why.)
If I set my SDK method with a transaction though, the outer code crashed with a TransactionAbortedException:
System.Transactions.TransactionAbortedException : The transaction has aborted.
---- Npgsql.PostgresException : 55000: prepared transactions are disabled
Currently we're using enlist=false at the SDK's connection string to prevent the inner transaction from joining the outer one but I'd like to know the reason behind this behavior.
Here's the code I'm reproducing the problem with:
using (var scope = new TransactionScope(
TransactionScopeOption.Required,
new TransactionOptions
{
IsolationLevel = IsolationLevel.ReadCommitted,
},
TransactionScopeAsyncFlowOption.Enabled))
{
await using (var conn = new SqlConnection(#"Server=(localdb)\mssqllocaldb;Database=Test;ConnectRetryCount=0"))
using (var cmd = new SqlCommand("insert into [Test].[dbo].[Test] (Id, \"Name\") values (1, 'A')", conn))
{
await conn.OpenAsync();
var result = await cmd.ExecuteNonQueryAsync();
await SdkMethodToDoStuffWithNpgsql(1);
scope.Complete();
}
}
I had SdkMethodToDoStuffWithNpgsql() to mock a method in a repository with Postgres context injected.
public async Task SdkMethodToDoStuffWithNpgsql(long id)
{
var sqlScript = #"UPDATE test SET is_removal = TRUE WHERE is_removal = FALSE AND id = #id;
INSERT INTO log(id, data) SELECT id, data FROM log WHERE id = #id";
using (var scope = new TransactionScope(
TransactionScopeOption.RequiresNew,
new TransactionOptions
{
IsolationLevel = IsolationLevel.ReadCommitted,
},
TransactionScopeAsyncFlowOption.Enabled))
{
await using (var conn = new NpgsqlConnection(this._context.ConnectionString))
{
await conn.OpenAsync();
using (var cmd = new NpgsqlCommand(sqlScript, conn))
{
cmd.Parameters.Add(new NpgsqlParameter("id", NpgsqlDbType.Bigint) { Value = id });
await cmd.PrepareAsync();
var result = await cmd.ExecuteNonQueryAsync();
if (result != 2)
{
throw new InvalidOperationException("failed");
}
scope.Complete();
}
}
}
}
The above is the expected behavior - enlisting two connections in the same TransactionScope triggers a "distributed transaction"; this is known in PostgreSQL terminology as a "prepared transaction", and you must enable it in the configuration (this is the cause of the error you're seeing above). If the intention is to have two separate transactions (one for SQL Server, one for PostgreSQL) which commit separately, then opting out of enlisting is the right thing to do. You should also be able to use TransactopScopeOption.Suppress.
Note that distributed transactions aren't currently supported in .NET Core, only in .NET Framework (see this issue). So unless you're on .NET Framework, this won't work even if you enable prepared transactions in PostgreSQL.

How to get a SqlTransaction object from a EF Core 5 DBContext transaction object as I need to pass it to SqlBulkCopy operation

I'm trying to start a transaction on DbContext and doing some operation on context and then wants to pass the same transaction to SqlBulkCopy operation as 3rd parameter.
In EF Core 5, DbContent class I did not find a way to get a SqlTransaction/DbTransaction object which can be passed to SqlBulkCopy operation. In code _contextTransaction object is of type DbContextTransaction and It seems it is a breaking change from MS in latest EF Core. I have added [not compatible] in the code for easy understanding.
If someone can suggest a workaround/solution.
using (var _context = new DBContext())
{
using (var _contextTransaction = _context.Database.BeginTransaction())
{
_context.SomeEntity.Add(obj);
_context.SaveChanges();
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(_context.Database.GetDbConnection() as SqlConnection, SqlBulkCopyOptions.Default, _context.Database.CurrentTransaction [not compatible]))
{
bulkCopy.DestinationTableName = "SomeTable";
bulkCopy.BulkCopyTimeout = 10000;
bulkCopy.BatchSize = 10000;
...........
await bulkCopy.WriteToServerAsync(partition);
}
}
}

How to use Dapper asynchronously with multiple stored procedure calls?

I'm using the Dapper ORM in an ASP.Net Core 2.1 CRUD application, with a SQL Server database. For a new form I'm developing, I want to retrieve all reference data (to populate SELECT field options) in one go when the screen is invoked. This involves a series of stored procedure calls, which I want to do asynchronously for best performance.
This Dapper tutorial suggests I should look at using QueryMultipleAsync, but I can't find an example of its use with stored procedures, only hard-coded SQL statements.
My C# code currently looks like this:
public async Task<ContactReferenceData> Get()
{
ContactReferenceData refData = new ContactReferenceData();
try
{
using (IDbConnection dbConnection = _connection)
{
dbConnection.Open();
var countryData = await dbConnection.QueryAsync<Country>(sql: "usp_GetCountries", commandType: CommandType.StoredProcedure);
refData.CountryDetails = countryData.AsList();
var companyData = await dbConnection.QueryAsync<Company>(sql: "usp_GetCompanies", commandType: CommandType.StoredProcedure);
refData.CompanyDetails = companyData.AsList();
var groupData = await dbConnection.QueryAsync<Group>(sql: "usp_GetGroups", commandType: CommandType.StoredProcedure);
refData.GroupDetails = groupData.AsList();
var groupPositionData = await dbConnection.QueryAsync<GroupPosition>(sql: "usp_GetGroupPositions", commandType: CommandType.StoredProcedure);
refData.GroupPositionDetails = groupPositionData.AsList();
}
return refData;
}
catch (Exception ex)
{
_logger.LogError(ex.ToString());
throw;
}
}
This works OK in my test environment, but I'm not sure it's the correct way to execute async queries. In particular, I have the following concerns:
is it robust enough to be trusted in live operation?
in its current form, is it maximising the benefits (if any) of asynchronous operation, or should I be using QueryMultipleAsync to properly achieve this?
Have you tried something like this?
public async Task<ContactReferenceData> Get()
{
var sql = "EXEC usp_GetCountries; EXEC usp_GetCompanies; EXEC usp_GetGroups; EXEC usp_GetGroupPositions";
ContactReferenceData refData = new ContactReferenceData();
try
{
using (IDbConnection dbConnection = _connection)
{
using (var multi = connection.QueryMultipleAsync(sql: sql, commandType: CommandType.StoredProcedure ).Result)
{
refData.CountryDetails = multi.Read<countryDetails>().ToList();
refData.CompanyDetails = multi.Read<CompanyDetails>().ToList();
refData.GroupData = multi.Read<Groups>().ToList();
refData.GroupPositionsData= multi.Read<GroupPositions>().ToList();
}
}
return refData;
}
catch (Exception ex)
{
_logger.LogError(ex.ToString());
throw;
}
}

Backup of the database in entity framework

i working with entity famework i need to transfer that code
RESTORE DATABASE [showing8-5-2013] FROM DISK = N'C:\Program Files (x86)\Microsoft SQL Server\MSSQL10_50.SQLEXPRESS\MSSQL\Backup\Company.bak' WITH FILE = 1, NOUNLOAD, REPLACE, STATS = 10
to code Entity frame work
any help thanks
EF is a DB neutral provider concept. Such commands are by their nature DB specific. EF exposes a way to execute an SQL command:
MyContext.Database.ExecuteSqlCommand();
But you may as well just do it directly.
Pass your SQL command into a custom routine eg:
private static bool ExecuteSqlStatement(string connectionString, string statement) {
int rowsAffected;
using (var sqlConnection = new SqlConnection(connectionString)) {
using (var sqlCommand = new SqlCommand(statement, sqlConnection)) {
try {
sqlConnection.Open();
rowsAffected = sqlCommand.ExecuteNonQuery();
}
catch (Exception ex) {
// your handler or re-throw....
return false;
}
}
}
return rowsAffected == -1;
// see http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.executenonquery.aspx
}

Retrieving a record from a stored procedure in asp.net

I am very new to ASP.NET so I apologize for the naive question but I was just wondering how do I retrieve the data from a stored procedure I am calling from within ASP.NET .The stored procedure is supposed to return a single row and I want to retrieve the record fields returned.
So this is what I have come up with so far
The stored Procedure
ALTER PROCEDURE dbo.StoredProcedure6
#LoginName varchar(50)
AS
SELECT username ,Password FROM dbo.Users
Where username = #LoginName
RETURN
The code to get access to the specific record within the asp.net.cs file
var user = dbcontext.returnuserdetails(txtEmailAddress.Text);
where returnuserdetails is the function I added via the model browser in Visual studio 2010
Now the question is how do I get and store the values of the username and password which are returned ?
I am working in ASP.NET 4.0 if it helps.
Thanks
if you are in 4.0 you can easily just use the LINQ to SQL stuff, no need for stored procedure here.
private void GetUser(string emailAddress){
using(DataContext dbcontext = new DataContext()){
var AppData.user = dbcontext.users
.Select(u => u.email_address == emailAddress).SingleOrDefault();
// access entity properties as needed
// user.email_address, user.first_name, etc..
}
}
That said you aren't really stating what it is you are trying to do with the user entity and passwords should NEVER be stored as plain text.
if you are forced to use Stored Procedures then the return in LINQ-to-SQL will always be a set.
ALTER PROCEDURE dbo.ReturnUserDetails
#LoginName varchar(50)
AS
SELECT * -- Get whole row so you have all info that is possibly needed
FROM dbo.Users
Where username = #LoginName
RETURN
C# Code
private void GetUser(string userName){
using(DataContext dbcontext = new DataContext()){
var user = dbcontext.ReturnUserDetails(userName).SingleOrDefault();
// access entity properties as needed
string userName = user.username;
var password = user.Password;
}
}
Use SqlDataReader Class
Edit:
This is a code sample from the link, now the difference between this sample and your case is that you should specify you command type as StoredProcedure.
If it still doesn't help let me know.
private static void ReadOrderData(string connectionString)
{
string queryString =
"SELECT OrderID, CustomerID FROM dbo.Orders;";
using (SqlConnection connection =
new SqlConnection(connectionString))
{
SqlCommand command =
new SqlCommand(queryString, connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
// Call Read before accessing data.
while (reader.Read())
{
Console.WriteLine(String.Format("{0}, {1}",
reader[0], reader[1]));
}
// Call Close when done reading.
reader.Close();
}
}

Resources