string connectionString = ConfigurationManager.ConnectionStrings["myConnection"].ConnectionString;
const string query = "my Select query here";
List<long> myList = new List<long>();
using (SqlConnection con = new SqlConnection(connectionString))
{
con.Open();
using (SqlCommand selectCommand = new SqlCommand(query, con))
{
selectCommand.CommandType = CommandType.Text;
SqlDataReader sqlreader = selectCommand.ExecuteReader();
while (sqlreader.Read())
{
long Id = (long)sqlreader["Id"];
List.Add(Convert.ToInt32(sqlreader[0].ToString()));
using (SqlCommand insertCommand = new SqlCommand("dbo.SP_Data", con))
{
insertCommand.CommandType = CommandType.StoredProcedure;
insertCommand.Parameters.Add("#Id", SqlDbType.BigInt).Value = Id;
insertCommand.Parameters.Add("#StatusId", SqlDbType.BigInt).Value = 1;
insertCommand.Parameters.Add("#ReportDate", SqlDbType.DateTime).Value = DateTime.Now;
insertCommand.Parameters.Add("#CreatedDate", SqlDbType.DateTime).Value = DateTime.Now;
insertCommand.Parameters.Add("#CreatedBy", SqlDbType.UniqueIdentifier).Value = DefaultUser();
insertCommand.ExecuteNonQuery();
}
}
}
}
I am getting the error "There is already an open DataReader associated with this Command which must be closed first." at the last line [insertCommand.ExecuteNonQuery();
You need to enalbe MARS in your connection string (MARS = Multiple Active Result Sets)
In short, this particular flag, when enabled in the connection string, allows to use the same connection used by the SqlDataReader also for executing commands. Otherwise, as stated by MSDN the connection is busy serving the SqlDataReader and cannot execute other commands.
Before Sql Server 2005 the developpers were forced to create, open and use another connection. (Still possible if your environment doesn't allow to change the connection string)
More info about MARS could be found on this MSDN article
Examples of connection string that uses MARS
Related
I have setup Managed Identity on my App Service and given the database access.
I have a console app and used Microsoft.Data.SqlClient 3.0.1 as a nuget package that I test the connection as follows:
string ConnectionString1 = #"Server=demo-server.database.windows.net;
Authentication=Active Directory Managed Identity; Encrypt=True; Database=DEMO";
using (SqlConnection conn = new SqlConnection(ConnectionString1))
{
conn.Open();
}
But get the error ‘Invalid value for key authentication’
Can anyone help with this ?
Updated code:
static void Main()
{
string str = #"Server=demo-server.database.windows.net;
Authentication=Active Directory Default; Database=DEMO";
string qs = "SELECT OrderID, CustomerID FROM dbo.Orders;";
CreateCommand(qs, str);
}
private static void CreateCommand(string queryString,
string connectionString)
{
using (SqlConnection connection = new SqlConnection(
connectionString))
{
SqlCommand command = new SqlCommand(queryString, connection);
command.Connection.Open();
command.ExecuteNonQuery();
}
}
}
UPDATE 2: Working code
string ConnectionString = #"Server=demo-server.database.windows.net,1433;Authentication=Active Directory Default; Encrypt=True;Database=DEMO";
using (Microsoft.Data.SqlClient.SqlConnection conn = new Microsoft.Data.SqlClient.SqlConnection(ConnectionString))
//conn.Open();
using (Microsoft.Data.SqlClient.SqlCommand command = new Microsoft.Data.SqlClient.SqlCommand("SELECT OrderID FROM dbo.Orders;", conn))
{
command.Connection.Open();
using (Microsoft.Data.SqlClient.SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine("\t{0}", reader.GetString(0));
}
}
}
It seems its how i was calling the using clause
You should follow the guidance in the link:
https://learn.microsoft.com/en-us/azure/app-service/tutorial-connect-msi-sql-database?tabs=windowsclient%2Cef%2Cdotnet
and take a look here in case you use a user-assigned managed identity (UAMI) https://learn.microsoft.com/en-us/sql/connect/ado-net/sql/azure-active-directory-authentication?view=sql-server-ver16
You did not state if you use UAMI or SAMI, if you use UAMI, then:
"For a user-assigned managed identity, the client id of the managed identity must be provided when using Microsoft.Data.SqlClient v3.0 or newer."
Also for the UAMI, you can try to use "User ID =" the Object Principal ID instead of the ClientID.
User ID=[PrincipalId]
Update
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.AccessToken = token.Token;
SqlCommand command = new SqlCommand(queryString, connection);
command.Connection.Open();
command.ExecuteNonQuery();
}
https://github.com/MicrosoftDocs/azure-docs/issues/103115
I am getting the deadlock found when trying to get lock; try restarting transaction exception while executing my below code
for(Map.Entry<Area, List<FranchiseTimeSlots>> entry : areaFranchiseTimeSlotsMap.entrySet()) {
Transaction txn = sessionFactory.getCurrentSession().beginTransaction();
Area area = entry.getKey();
List<FranchiseTimeSlots> franchiseTimeSlotsList = entry.getValue();
List<Integer> franchiseTimeSlotIds = new ArrayList<>();
franchiseTimeSlotsList.forEach(x -> franchiseTimeSlotIds.add(x.getId()));
String queryString = "Delete from franchise_timeslot_areas fta where fta.FRANCHISE_TIMESLOT in (:franchiseTimeSlotIds) AND fta.AREA =:areaID";
Query query = sessionFactory.getCurrentSession().createNativeQuery(queryString);
query.setParameter("areaID",area.getId());
query.setParameterList("franchiseTimeSlotIds",franchiseTimeSlotIds);
query.executeUpdate();
String updateQueryString = "update franchise_timeslot ft set ft.UPDATED_DATE=:date,ft.UPDATED_BY=:userID where ft.ID in (:franchiseTimeSlotsIds)";
Query query1 = sessionFactory.getCurrentSession().createNativeQuery(updateQueryString);
query1.setParameter("userID",user.getId());
query1.setParameter("date",new Date());
query1.setParameterList("franchiseTimeSlotsIds",franchiseTimeSlotIds);
query1.executeUpdate();
txn.commit();
I am writing a database application using Visual Studio 2012 with Entity Framework 5 and SQL Server 2008. I would like Entity Framework to impersonate a SQL Server user (i.e. user without a login). I have created a new constructor for the DB context MyDatabaseEntities which includes an argument for the name of the user to impersonate. Here is the code that I've written:
public partial class MyDatabaseEntities
{
private String _impersonateUser = null;
public MyDatabaseEntities(String impersonateUser)
: base("MyConnectionString")
{
_impersonateUser = impersonateUser;
this.Database.Connection.StateChange += Connection_StateChange;
}
void Connection_StateChange(object sender, StateChangeEventArgs e)
{
if (e.CurrentState == ConnectionState.Open && e.OriginalState != ConnectionState.Open)
{
using (var cmd = this.Database.Connection.CreateCommand())
{
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add(new SqlParameter("user", _impersonateUser));
cmd.CommandText = "EXECUTE AS USER = #user";
cmd.ExecuteNonQuery();
}
}
}
I had to add the check...
if (e.CurrentState == ConnectionState.Open && e.OriginalState != ConnectionState.Open)
...because the method Connection_StateChange method seems to execute even when the state hasn't changed. Then problem is that when I run the code twice,
public void RunSimpleQuery()
{
using (MyDatabaseEntities context = new MyDatabaseEntities("UserName"))
{
var result = context.TableName.ToList();
}
}
...Entity Framework throws a SqlException:
A severe error occurred on the current command. The results, if
any, should be discarded.\r\nA severe error occurred on the current
command. The results, if any, should be discarded.
Any ideas?
Update 1
I in my code above, I changed...
cmd.CommandText = "EXECUTE AS USER = #user;";
...to...
cmd.CommandText = "REVERT; EXECUTE AS USER = #user;";
...and I still get the same SqlException error.
The problem is that EF closes connection when it doesn't need it and returns it back to the pool. So when it executes some SQL again it request new connection from the pool where your event may not be initialized. But again I believe that you should try to solve this with manually controlling connection lifetime to have both benefit of connection pooling and be able to meet your requirements.
I know is an old question, but maybe will be useful for someone.
I did in a different way, using your code...
Instead of
Connection_StateChanged event
I create two methods in the same class:
public void ChangeUser(String sUser)
{
if(Database.Connection.State != ConnectionState.Open)
Database.Connection.Open();
using (var cmd = Database.Connection.CreateCommand())
{
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add(new SqlParameter("user", sUser));
cmd.CommandText = "EXECUTE AS USER = #user;";
cmd.ExecuteNonQuery();
}
}
public void Revert()
{
if (Database.Connection.State != ConnectionState.Open)
Database.Connection.Open();
using (var cmd = Database.Connection.CreateCommand())
{
cmd.CommandType = CommandType.Text;
cmd.CommandText = "REVERT;";
cmd.ExecuteNonQuery();
}
}
I use it before and after execute stored procedure,
using (var db = new MyDatabaseEntities())
{
db.ChangeUser(model.Username);
var result = db.Something();
db.Revert();
return result;
}
It works fine with SPs and it doesn't throw an exception even after many executions. If I could catch an event after command execute, maybe all be encapsulated on MyDatabaseEntities.
Using subsonic 3 I have a project with a bit of a weird scenario. I have a .net windows service that needs to connect to a master database which stores connections to other database servers and also a set of tables for processing automated SMS messages. Then I have identical databases on the other servers (the connection string table is empty on the other db's) that handle the messages for other applications.
So, subsonic can call to all of the DB's just fine using the connection string/provider name options.
public static List<SMSRequestWithResponseList> SMSRequestListGetAll(string applicationName)
{
string connStr = GetConnectionStringByApplicationName(applicationName);
List<SMSRequestWithResponseList> response = new List<SMSRequestWithResponseList>();
List<DAL.CDYNESMSRequest> lst = DAL.CDYNESMSRequest.All(connStr, providerName).ToList();
foreach (DAL.CDYNESMSRequest mitm in lst)
{
SMSRequestWithResponseList itm = new SMSRequestWithResponseList(mitm, mitm.CDYNESMSResponses.ToList(), string.Empty);
response.Add(itm);
}
return response;
}
The issue is saving...Insert seems to be working.
DAL.CDYNESMSRequest itm = new DAL.CDYNESMSRequest(connStr, providerName).;
itm.KeyCode = KeyCode;
itm.ApplicationName = ApplicationName;
itm.BatchTransaction = BatchTransaction;
itm.AssignedDID = GetParameter("AssignedDID");
itm.PhoneNumber = PhoneNumber;
itm.MessageDetail = MessageText;
itm.MessageCancelled = false;
itm.MessageQueued = false;
itm.MessageSent = false;
itm.IsImmediate = SendImmediate;
itm.InQueue = false;
itm.ScheduledDateTime = ScheduledDateTime;
itm.CreateDT = dt;
itm.ModifiedDT = dt;
itm.Save();
But it doesn't seem to want to update...
DAL.CDYNESMSRequest itm = DAL.CDYNESMSRequest.SingleOrDefault(x => x.RequestID == requestID, connStr, providerName);
if (itm != null)
{
itm.MessageID = messageGUID;
itm.MessageCancelled = messageCancelled;
itm.MessageQueued = messageQueued;
itm.ReferenceID = messageReferenceID;
itm.MessageSent = messageSent;
if (messageSentDT < new DateTime(1753, 1, 1, 0, 0, 0))
itm.MessageSentDT = null;
else
itm.MessageSentDT = messageSentDT;
itm.MessageSMSError = messageSMSError;
itm.ModifiedDT = dt;
itm.Save();
}
I'm calling using the connection string from the correct database but it doesn't update the record.
If I'm saving it incorrectly please let me know. I did try to create a new provider and set it on the save but it barked at me saying it already had an open connection.
Thanks!
Don't use ActiveRecord pattern, but the SimpleRepository which allows you to setup multiple repos and you can specify a connectionstring per repo.
// not sure if this is the right constructor or if it's providerName, connectionString
var repo1 = new SimpleRepository(connectionString1, providerName);
var repo2 = new SimpleRepository(connectionString2, providerName);
var item = repo1.Single<Product>(1);
if (repo2.Exists<Product>(x => x.Id == item.Id))
repo2.Update(item);
else
repo2.Add(item);
Porting MSSQL Application to Sybase (ASE 15.0), and experiencing a problem when I call GetDeleteCommand.
The error reported is:
Dynamic SQL generation for the DeleteCommand is not supported against
a SelectCommand that does not return any key column information.
The problem only occurs for temporary table, identical non-temporary table works fine.
Table contains a primary key.
Reproduced using test program below.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.OleDb;
using System.Data;
namespace DataAdapterTempTable
{
class Program
{
static void Main(string[] args)
{
String ConnectionString = "Provider=ASEOLEDB;Data Source=devsun3:5003;Initial Catalog=ctc;User ID=aigtac12;Password=aigtac12;"; // sybase connection string
//String ConnectionString = "Provider=SQLOLEDB;Data Source=fiji;Persist Security Info=False;Initial Catalog=nxgn0811;Integrated Security=SSPI"; // mssql connection string
String TableName = "#alex_temporary_table_test"; // does not work for sybase
//String TableName = "alex_real_table_test"; // works for sybase + mssql
String CreateStatement = "create table " + TableName + " (currency_id varchar(4) primary key, rate decimal(25,6), format char(1))";
String SelectStatement = "select * from " + TableName;
try
{
OleDbConnection con = null;
con = new OleDbConnection(ConnectionString);
con.Open();
OleDbCommand cmd = con.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = CreateStatement;
int count = cmd.ExecuteNonQuery();
OleDbCommand cm1 = con.CreateCommand();
cm1.CommandType = CommandType.Text;
cm1.CommandText = SelectStatement;
OleDbDataAdapter DA2 = new OleDbDataAdapter(cm1);
DataTable DT2 = new DataTable();
DA2.FillSchema(DT2, SchemaType.Mapped);
OleDbCommandBuilder cmdbldr = new OleDbCommandBuilder(DA2);
DA2.InsertCommand = cmdbldr.GetInsertCommand();
DA2.DeleteCommand = cmdbldr.GetDeleteCommand(); // this line fails in sybase for temporary table
DA2.UpdateCommand = cmdbldr.GetUpdateCommand();
DA2.Fill(DT2);
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
}
In the select statement, instead of * use the column names.
Contacted Sybase support, turns out I had to update some system stored procedures. There is a folder that ends with "oledb\sp", and I had to run a .bat file from the folder. I got the latest ebf and ran the batch file install_oledb_sprocs.bat, the problem went away. Worth mentioning, that sybase 15.5 did not have the issue without patching.
P.S. Thank you to 'aF' for your time looking into the issue.