Dapper not adding parameters - sql

I am trying to use Dapper for our complex queries to remove any lost overhead that was previously existing with NH.
I have the following query (note this has been considerably shrunk):
SELECT DISTINCT *
FROM tasks t
WHERE t.initials = #UserInits
Which is called via our repository as so:
taskRepo.RawExec<TaskListItemDTO>(Query,new {UserInits = "SAS"})
Our implementation of DapperExec consist as follows:
public IEnumerable<T> RawExec<T>(string SQL, object param)
{
return _session.Connection.Query<T>(SQL,param);
}
But Dapper doesn't appear to be adding the parameters to the query, and as a result, we are getting syntax errors.
Incase it helps, we are connecting over ODBC to Informix.
Thanks
Update Code Sample:
Sorry it took so long, been very busy with work! Below is a sample for MS SQL (2008) Server that should simple query the sys.all_objects (systables?) with a param value of 1 or 0 - but in this sample, as ODBC does not use named params, this won't work.
using Dapper;
using DapperSQL;
using System.Collections.Generic;
using System.Data;
using System.Data.Odbc;
namespace DapperTests
{
public class SQLEx
{
private OdbcConnection GetConnection()
{
var cnn = new OdbcConnection("DSN=ODBCSOURCE");
cnn.Open();
// wrap the connection with a profiling connection that tracks timings
return cnn;
}
public IEnumerable<object> DapperTest()
{
using (OdbcConnection conn = GetConnection())
{
return conn.Query("SELECT * FROM sys.all_objects where is_ms_shipped = ?", new { is_ms_shipped = 1 });
}
}
}

I know this is old post, just use SP instead of query, please check this link Dapper using ODBC store procedure Input parm, this using sybase odbc Sp, all odbc use same technique, I wish it works in Informix.

Related

Is it better to create Single or multiple SQL connection to execute same query multiple time?

I'm executing same command in every 2 seconds. I think following code creates multiple connections:
[System.Web.Services.WebMethod]
public static int getActivity()
{
using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["dbconnection"].ToString()))
{
connection.Open();
using (var cmd = new SqlCommand("SELECT TOP 1 ValueX FROM TABLE WHERE ID= 2 AND EVENTID = 2 ORDER BY DATE DESC", connection))
{
var x = cmd.ExecuteScalar();
int Result;
if (x != null)
{
Result = int.Parse(x.ToString());
Console.WriteLine("USER ACTIVITY : " + Result);
}
else
{
Result = -999;
}
connection.Close();
return Result;
}
}
}
If I call this method several time Does following code make multi connection Or single connection ?
using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["dbconnection"].ToString()))
Can someone explain whether I need to modify this code or Is this good one ?
Thanks.
Since you are using the using statement clause so once you are done with the method the resources are freed and the connection is closed. So everytime when you call the same method a new connection will be made. When you are using the using clause then it is equivalent to the below code:
SqlConnection connection = null;
try
{
connection = new SqlConnection(connectionString);
}
finally
{
if(connection != null)
((IDisposable)connection).Dispose();
}
Also note that you dont need to explicitly call the connection.Close(); in your method as using statement will take care of it.
Your method is fine, you just don't need connection.Close() as described by Rahul. Using statement when dealing with SQL objects is good practice.
What you should keep in mind, is that ADO.NET connection pooling, takes care of handling new objects referring to the same connection string, thus minimizing the time needed to open a connection.
More about connection pooling can be found Here

REST API (JSON) that updates SQL Table using Windows Console Application and Scheduled Tasks

I am a newbie at JSON programming. Most of my experience is in C# and some in XML and Javascript. So I am a bit lost. I will attempt to be as specific as possible.
I have written a windows console application that runs via the task scheduler. Basically the windows application is supposed to take the API from a site that is managed by an outside company but the information is owned by my company and put the information within a SQL table. The API is pretty standard and written in JSON.
I am successful in parsing the JSON language and (for example) displaying it in a command prompt but I need to be able to parse the language and place it into an SQL table. I have read up on SQL injection attacks and I feel fairly confident that we have covered our bases here. So the problem lies in the fact that it does not update the table when the application is run via the scheduler or without the scheduler.
I have included a little bit of the JSON language below along with the language for my console application.
{"date":"2015-09-24","data":[{"cid":"17","rank":1},{"cid":"26","rank":1},{"cid":"80","rank":1},{"cid":"30","rank":1},{"cid":"90","rank":1},{"cid":"62","rank":1},{"cid":"147","rank":1},{"cid":"28","rank":1}"s":1,"e":null}
using System;
using System.Collections;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Formatting;
using System.Threading.Tasks;
using System.Net;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace JsonApiClient
{
class Program
{
static void Main(string[] args)
{
ExecuteRiskSearch();
Console.ReadLine();
}
static void ExecuteRiskSearch()
{
string url = "https://localhost/api/getWatchList/";
string json = new WebClient().DownloadString(url);
JObject results = JObject.Parse(json);
foreach (var result in results)
{
string cid = (string)results["CID"];
JToken rank = results["rank"];
string risk = "";
if (rank is JValue)
{
risk = (string)rank;
}
else if (rank is JArray)
{
risk = (string)((JArray)rank).First;
}
else
{
SqlConnection connection = null;
SqlCommand command = null;
try
{
connection = new SqlConnection("Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=apiData;Data Source=serverName;");
command = new SqlCommand("UPDATE apiData.dbo.API SET [Category] WHERE CID=CID", connection);
connection.Open();
int numrows = command.ExecuteNonQuery();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
finally
{
command.Dispose();
connection.Dispose();
}
}
}
}
}
}
What am I missing to make the JSON data update my SQL table? I have scoured Google search results and I haven't found much information. Any help would be so greatly appreciated.
For the need to foreach with the correct part of the JSON object, what I mean is very simply that your variable results includes the entire JSON object, from the "date" through the "e". You need to start with the "data" object and iterate through its array or your string cid will error out on assignment, as it will be attempting to assign an array to a single value. The same goes for your JToken rank. I believe it should be this:
foreach(datum in results["data"])
{
string cid = datum["cid"];
JToken rank = datum["rank"];
/* ... */
}
In addition, your set command isn't doing anything. You need to use SET columName = " + newValue + " WHERE CID == " + cid to actually affect a change, where columnName is the column you wish to alter and newValue is your C# variable carrying the desired replacement.
It's also a best practice to include a change to an updated date field when updating via an automated process, if there is one present. Generally the convention is to have a created date and an updated date for each row in a table.
I hope this at least points you in the right direction.
-C§
As an alternative, you can send entire text to Sql Server and load it there.
Sql Server 2016 will enable you to store JSON using single command - OPENJSON. In the older versions you can use existing CLR/JSON libraries such as Json4Sql or JsonSelect.

How to implement SQL Azure Transient Fault Handling Framework for Dapper?

I'm a vb.net guy and have difficulty reading C#. I compiled the C# Dapper to a DLL and use it my app.
My main concern is I think I need to modify the source to integrate by default the Transient Fault Handling Framework for SQL Azure in each SQL query.
I can add the retry logic on the connection level because it is ont top of dapper, but not at the execute query level which is embedded in drapper class.
Anyone has done that yet ?
* UPDATE *
Does using only ReliableSqlConnection on top of Dapper call will handle a retry logic on the execute non query ?
Here is sample code of retry from MS with the transietn fault hanling
using Microsoft.Practices.EnterpriseLibrary.WindowsAzure.TransientFaultHandling;
using Microsoft.Practices.EnterpriseLibrary.WindowsAzure.TransientFaultHandling.AzureStorage;
using Microsoft.Practices.EnterpriseLibrary.WindowsAzure.TransientFaultHandling.SqlAzure;
using System.Data;
...
using (ReliableSqlConnection conn = new ReliableSqlConnection(connString, retryPolicy))
{
conn.Open();
IDbCommand selectCommand = conn.CreateCommand();
selectCommand.CommandText =
"UPDATE Application SET [DateUpdated] = getdate()";
// Execute the above query using a retry-aware ExecuteCommand method which
// will automatically retry if the query has failed (or connection was
// dropped).
int recordsAffected = conn.ExecuteCommand(selectCommand, retryPolicy);
}
Here is the execute part of Dapper code, same name is used but I guess it is a custom execute function
private static int ExecuteCommand(IDbConnection cnn, IDbTransaction transaction, string sql, Action<IDbCommand, object> paramReader, object obj, int? commandTimeout, CommandType? commandType)
{
IDbCommand cmd = null;
bool wasClosed = cnn.State == ConnectionState.Closed;
try
{
cmd = SetupCommand(cnn, transaction, sql, paramReader, obj, commandTimeout, commandType);
if (wasClosed) cnn.Open();
return cmd.ExecuteNonQuery();
}
finally
{
if (wasClosed) cnn.Close();
if (cmd != null) cmd.Dispose();
}
}
I would recommend wrapping the retry around Dapper, preferably by using the RetryPolicy.ExecuteAction method. That way both the OPEN call to the connection
and the command itself will be retried using the TFH retry policy:
For example:
SqlRetryPolicy.ExecuteAction(() =>
{
// Place Dapper ExecuteCommand here: e.g.
ExecuteCommand(conn, trans, ... )
});

Using SMO Library in SSIS 2008

Good afternoon,
Im having some trouble writing a simple script using SMO objects in C# to validate if an object exists and then create it. This code is within a Script Task Component in SSIS. The code executes successfully, however the new database does not show up on my local instance. Any help would be greatly appreciated.
using System;
using System.Data;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
using System.Collections;
using System.Data.SqlClient;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;
public void Main()
{
//String DBName = Dts.Variables["TmpViewDBName"].Value.ToString();
//String Instance = Dts.Variables["TmpViewDBInstance"].Value.ToString();
String DBName = "localhost";
String Instance = "TmpViewDB";
Server TmpViewServer = new Server(Instance);
//Windows Auth
TmpViewServer.ConnectionContext.LoginSecure = true;
TmpViewServer.ConnectionContext.Connect();
if (TmpViewServer.Databases[DBName] != null)
{
TmpViewServer.Databases[DBName].Drop();
}
Database TmpViewDB = new Database(TmpViewServer, DBName);
if (TmpViewServer.ConnectionContext.IsOpen)
TmpViewServer.ConnectionContext.Disconnect();
Dts.TaskResult = (int)ScriptResults.Success;
}
I believe you need to add a line to actually create the object. As it stands now, you've only instantiated the object but never actually made the call to the database to create the remote object.
Database TmpViewDB = new Database(TmpViewServer, DBName);
TmpViewDB.Create();

How to intercept and modify SQL query in Linq to SQL

I was wondering if there is any way to intercept and modify the sql generated from linq to Sql before the query is sent off?
Basically, we have a record security layer, that given a query like 'select * from records' it will modify the query to be something like 'select * from records WHERE [somesecurityfilter]'
I am trying to find the best way to intercept and modify the sql before its executed by the linq to sql provider.
Ok, first to directly answer your question (but read on for words of caution ;)), there is a way, albeit a finicky one, to do what you want.
// IQueryable<Customer> L2S query definition, db is DataContext (AdventureWorks)
var cs = from c in db.Customers
select c;
// extract command and append your stuff
DbCommand dbc = db.GetCommand(cs);
dbc.CommandText += " WHERE MiddleName = 'M.'";
// modify command and execute letting data context map it to IEnumerable<T>
var result = db.ExecuteQuery<Customer>(dbc.CommandText, new object[] { });
Now, the caveats.
You have to know which query is generated so you would know how to modify it, this prolongs development.
It falls out of L2S framework and thus creates a possible gaping hole for sustainable development, if anyone modifies a Linq it will hurt.
If your Linq causes parameters (has a where or other extension causing a WHERE section to appear with constants) it complicates things, you'll have to extract and pass those parameters to ExecuteQuery
All in all, possible but very troublesome. That being said you should consider using .Where() extension as Yaakov suggested. If you want to centrally controll security on object level using this approach you can create an extension to handle it for you
static class MySecurityExtensions
{
public static IQueryable<Customer> ApplySecurity(this IQueryable<Customer> source)
{
return source.Where(x => x.MiddleName == "M.");
}
}
//...
// now apply it to any Customer query
var cs = (from c in db.Customers select c).ApplySecurity();
so if you modify ApplySecurity it will automatically be applied to all linq queries on Customer object.
If you want to intercept the SQL generated by L2S and fiddle with that, your best option is to create a wrapper classes for SqlConnection, SqlCommand, DbProviderFactory etc. Give a wrapped instance of SqlConnection to the L2S datacontext constructor overload that takes a db connection. In the wrapped connection you can replace the DbProviderFactory with your own custom DbProviderFactory-derived class that returns wrapped versions of SqlCommand etc.
E.g.:
//sample wrapped SqlConnection:
public class MySqlConnectionWrapper : SqlConnection
{
private SqlConnecction _sqlConn = null;
public MySqlConnectionWrapper(string connectString)
{
_sqlConn = new SqlConnection(connectString);
}
public override void Open()
{
_sqlConn.Open();
}
//TODO: override everything else and pass on to _sqlConn...
protected override DbProviderFactory DbProviderFactory
{
//todo: return wrapped provider factory...
}
}
When using:
using (SomeDataContext dc = new SomeDataContext(new MySqlConnectionWrapper("connect strng"))
{
var q = from x in dc.SomeTable select x;
//...etc...
}
That said, do you really want to go down that road? You'll need to be able to parse the SQL statements and queries generated by L2S in order to modify them properly. If you can instead modify the linq queries to append whatever you want to add to them, that is probably a better alternative.
Remember that Linq queries are composable, so you can add 'extras' in a separate method if you have something that you want to add to many queries.
first thing come to my mind is to modify the query and return the result in Non-LINQ format
//Get linq-query as datatable-schema
public DataTable ToDataTable(System.Data.Linq.DataContext ctx, object query)
{
if (query == null)
{
throw new ArgumentNullException("query");
}
IDbCommand cmd = ctx.GetCommand((IQueryable)query);
System.Data.SqlClient.SqlDataAdapter adapter = new System.Data.SqlClient.SqlDataAdapter();
adapter.SelectCommand = (System.Data.SqlClient.SqlCommand)cmd;
DataTable dt = new DataTable("sd");
try
{
cmd.Connection.Open();
adapter.FillSchema(dt, SchemaType.Source);
adapter.Fill(dt);
}
finally
{
cmd.Connection.Close();
}
return dt;
}
try to add your condition to the selectCommand and see if it helps.
Try setting up a view in the DB that applies the security filter to the records as needed, and then when retrieving records through L2S. This will ensure that the records that you need will not be returned.
Alternatively, add a .Where() to the query before it is submitted that will apply the security filter. This will allow you to apply the filter programmatically (in case it needs to change based on the scenario).