0

I am using Dapper to process data.

Here is a code sample:

using(var connection = new SqlConnection(ConfigurationManager.AppSettings["MyConnectString"])
{
     var sql = string.Format(
         @"SELECT [Column1]
             FROM [MyTable]
            WHERE [Column3] > {0}
              AND [Column4] < {1}"
         , myValue1
         , myValue2
     );
     var result = connection.Query<long>(sql).ToList();
}

My project writes many sql scripts like the one above.

I want to write scripts to files (maybe QueryAccount.config, QueryOrder.config, (xml format), or others)

Then I can load the script from the files.

What I want is write my scripts in files, then I write the same class in file. (eg. I write all query Product scripts in Product.config, and all query Order scripts in Order.config) Then I use like:

var cmd = MyCommandManager.GetScript("QueryProduct");
cmd.SetParam("@ProductId", 123);
cmd.SetParam("@InvoicingDate", DateTime.Now(-7))
...

Script in file like:

SELECT [ProductName]
FROM [Product]
WHERE [ProductId] = @ProductId
  AND [InvoicingDate] = @InvoicingDate
dotcoder
  • 2,828
  • 10
  • 34
  • 50
Max
  • 4,439
  • 2
  • 18
  • 32
  • 4
    don't do this - you are asking for sql injection attacks! – Daniel A. White Jan 09 '17 at 02:30
  • 3
    Why would you even want that? – Ilia G Jan 09 '17 at 02:32
  • You should create store procedures for each of your script, then just call those store procedures with parameters. It will avoid the sql injection. – Kim Hoang Jan 09 '17 at 02:34
  • @DanielA.White can you give me some suggestion for this? But I must use dapper...Thanks a lot. – Max Jan 09 '17 at 02:34
  • 2
    http://stackoverflow.com/questions/13653461/dapper-and-sql-injections – Daniel A. White Jan 09 '17 at 02:35
  • It's not even clear to me what you want to do here. Other than the SQL injection vulnerability that's already been pointed out, what's wrong with this? What are you looking to change? – David Jan 09 '17 at 02:40
  • @KimHoang: Not necessarily. Don't recommend a golden hammer if the programmer doesn't actually understand the problem being addressed. Any user-alterable value executed as SQL code is an avenue for SQL injection, regardless of whether or not it's part of a stored procedure. – David Jan 09 '17 at 02:44
  • @David I add some info what I think in the original question block. – Max Jan 09 '17 at 02:59
  • @Gary: Ok... But what have you tried and where are you stuck? The new information in the question sounds like you want us to write a data access library for you. Have you encountered a specific issue while attempting to implement this idea of yours? – David Jan 09 '17 at 03:00
  • @David Maybe I did not know how to descript clearly. I want to get some suggestions for file's format. I'm now use xml format to develope, but I want to know is there any better solution to solve the question like this, maybe someone can use json format (or others...) better to solve it simply. – Max Jan 09 '17 at 03:17
  • The query correctly uses parameters. There is no danger of SQL injection. The question is about getting the SQL out of string literals and into its own file. This is valid, and in fact, best practice. – bbsimonbb Jan 09 '17 at 09:12

2 Answers2

3

Ignore the downvoters. SQL should always be in its own file. These files should have the extension .sql, not .config. As such, they will be edited in the VS SQL editor, a real comfort. You want one file per query I think. Nothing is gained by grouping different queries in the same file. I would advocate putting these files next to the .cs files that consume them, grouping together files you open together, and files you're likely to want to delete together one day.

Once created, right click the .sql in solution explorer, Properties --> Build Action --> Embedded resource. Then, in your MyCommandManager.GetScript() method, use GetManifestResourceStream() to access the query text. Compared to stored procedures, this has the huge advantage that your queries are compiled with the calling code, so you never have to worry about synching the version of your stored procedures and your application.

If all this seems like a lot of work, it kinda is. That's why no one does it, but they should :-) Grab QueryFirst, and it will be done for you, and a lot else besides. Disclaimer : I wrote QueryFirst.

bbsimonbb
  • 27,056
  • 15
  • 80
  • 110
0

If you have full access to the database you can try to implement a Stored Procedure to store the SQL text. All you would need to do is reference the Stored Proc name in the Dapper query and set the command type to StoredProcedure and you will be good to go, like so:

using(var cn = new SqlConnection("MyConnectionString"))
{
    cn.Open();
    return cn.Query<MyModel>("MyProcName", new { Parameter1 = myValue1, Parameter2 = myValue2 }, commandType: CommandType.StoredProcedure);
}

Using SQL Paramters instead of injecting the values into your query is a very smart thing to do, as it prevents SQL Injection attacks. reformatting your query like so would help:

@"SELECT [Column1]
  FROM [MyTable]
  WHERE [Column3] > @Parameter1
  AND [Column4] < @Parameter2"

Notice my parameter names match the dapper call above. When I do not use Stored Procedures, however, I usually create a private const string at the top of the class that references the query for my "storage".

public class QueryClass 
{
    private const string query = "SELECT * FROM Table1";

    public IEnumerable<MyModel> CallQuery()
    {
        // Dapper Query Details
    }
}

I subscribe to a Command/Query Pattern like this one so I never have an issue with query storage since each class usually has one query.

EDIT

If you like the Command/Query pattern, I recommend you check out MediatR as it is a nice implementation of such pattern.

SECOND EDIT

I see what you are trying to do by adding the SQL Queries to some sort of config file, however if I can I would like to advise you against that. At my last job, all SQL Queries were stored in XML files that were compiled into the application. It seemed like an effective way to manage queries, but once the application grew to even a few SQL XML files we had a hard time managing what queries could be found where, and eventually we had queries duplicated in several XML files. We also had many problems with typo's and other XML structure errors that were not caught until runtime, but I guess you can have typo's in any string so that won't necessarily go away. It ends up being a mess and causing more problems than it solves.

I believe that having the SQL query text as close to the code that requires it as possible is a better alternative, and if you are clever about namespacing and organizing query objects, you can make it easy for devs to find a query via intellisense.

Carson
  • 1,169
  • 13
  • 36