Dapper (connection.Query or connection.Execute) - stored-procedures

I see the example of using Dapper in executing stored procedures with dynamic parameters, and returning the results of the procedure. Usually, the examples use .Execute, but a few of them use .Query. I have difficulty in using .Execute. Which am I supposed to use in the case described above--query or execute AND in what cases would I use each?

If you need to return a value, then use Query(). If you need to execute a query that does not return anything, an update for example, then use Execute().
Query example:
var myList = connection.Query("select * from myTable")
Execute example:
connection.Execute("update myTable set columnA = #value", new {value = "ABC"})

Related

How to specify a parameter as collection in Commandtext

I am using SqlCommandProvider and I need to get some data for each id in an id collection
let ids=["B058A99-C4B2-4CC3-BA9F-034B1F1ECCBD";"A09C01C-D51B-41C1-B44C-0995DD285088"]
[<Literal>]
let qLogo ="""SELECT Id,LogoUrl FROM Hotels WHERE Id IN (#IDS)"""
let queryLogo = new SqlCommandProvider<qLogo,constring>()
queryLogo .Execute(ids)//i need to be able to pass a collection here
`
Long story short, SqlCommandProvider is not even correct type provider to do this (assuming you don't consider string concatenation to build query). The reason is SQL Server only accepts array parameters through calling stored procedure and passing a Table Valued Parameter.
So, to call a stored procedure you need an SqlProgrammabilityProvider to achieve this. But you'll have to create Table Type and Stored Procedure up-front, as described in type provider documentation (scroll down to "Table-valued parameters (TVPs)" section).
Relevant discussion: How to use SQL IN statement in fsharp.data.sqlclient?

Setting a var equal to SQL code

I have a school PAT project where I need to do something extra, and in order to do so I need to do the following (I am using delphi 7 and ms access):
I want to set sql code = to a variable in order to use the var for something like a calculation.
I am thinking something like this:
s(var):=ADOQuery1.SQL.Text:='SELECT Birthdate where username = '+edtUsername.text;
So basically I want to set a specific ms access cell = to a var in delphi.
You trying to do too much in one line.
You set the SQL.Text
Then run the Query.
Then read one line into your variable.
Furthermore never inject parameters directly into a query; this leads to SQL injection vulnerabilities. Use parameters instead.
In pseudo code:
ADOQuery1.SQL.Text:='SELECT Birthdate where username = :name';
ADOQuery1.Parameters.ParamByName('name'):= aname; <<-- save way to use parameters.
ADOQuery1.RunQuery;
var1:= ADOQuery1.FieldByName('BirthDate').AsDate;
Obviously you need to fix the SQL statement, because it is incomplete and tweak the code a little. But I'll leave that as an exercise.
Here's the documentation for TADOQuery: http://docwiki.embarcadero.com/Libraries/XE5/en/Data.Win.ADODB.TADOQuery

LINQ join in VB.NET return concrete type rather than anonymous

I have the following LINQ query in VB.NET
Using db As New ReablementLSQLDataContext
query = (From b In db.Visits
Join c In db.LinkStaffToVisits On b.ID Equals c.VisitID
Where c.StaffID = staffid And b.StartEpoch = newepochdatetime).ToList()
End Using
When I run this, it returns a list of type anonymous which means its pretty useless if I want to access any of the data in it. How do I run this join statement and return a list of a concrete type?
Anonymous types as query results aren't so "useless", since you can always foreach over them (locally). Still, if you want a concrete type, you can add a select statement at the end and project the anonymous result into your type (supposed that you made this type and know which fields to use where), like (C# syntax)
var newQuery = query.Select(anon_x => new YourType(anon_x.field1, anon_x.field2, ...))
You can use a generic version of ToList method. I am a C# developer and can provide syntax related to C# :
.ToList<YourType>();
For VB.Net version read : http://msdn.microsoft.com/en-us/library/bb342261.aspx#Y0

LINQ to Entities does not recognize the method exception

I have some thing like this
SecuritySearcher sc = new SecuritySearcher();
Dictionary<string, bool> groupsMap =
sc.GetUserGroupMappings(domainName, currentUser, distGroups.ToList());
IQueryable<HotelTravel> groupq =
(from hotel in qHs
join hp in qHps on hotel.HotelTravelId equals hp.HotelTravelId
where !string.IsNullOrEmpty(hp.GroupName)
&& groupsMap.ContainsKey(hp.GroupName)
&& groupsMap[hp.GroupName] == true
select hotel);
While executing Linq statement it is throwing exception saying
LINQ to Entities does not recognize the method 'Boolean ContainsKey(System.String)' method, and this method cannot be translated into a store expression.
In order to translate your expression into a database query, the database would somehow have to know the contents of your dictionary and have a way to access it from the query. There is no dictionary mechanism in SQL, but that doesn't matter because you don't need a dictionary because you're just looking for keys whose value is a certain constant. You can turn that set of keys into a list and see if that list contains what you're looking for:
var groupsList = (from kvp in groupsMap // find all keys in groupsMap
where kvp.Value == true // where the value is set to True
select kvp.Key).ToList();
IQueryable<HotelTravel> groupq =
from hotel in qHs
join hp in qHps on hotel.HotelTravelId equals hp.HotelTravelId
where !string.IsNullOrEmpty(hp.GroupName)
&& groupsList.Contains(hp.GroupName)
select hotel;
I suspect that you don't actually have the empty string as a key in your dictionary, though, which means you can get rid of the IsNullOrEmpty call and just have where groupsList.Contains(hp.GroupName).
I had the same issue. The easiest solution is to replace the method
where groupsMap.ContainsKey(hp.GroupName)
with the method with the same functionality that is recognized by LINQ to Entities:
where groupsMap.Keys.Contains(hp.GroupName)
As the answer here says, these two functions do exactly the same thing.
You are not allowed to use your dictionary in the WHERE clause to limit your result set because LINQ To Entities will try to turn this into SQL and unfortunately, it doesn't know how to handle the Dictionary collection.
See this link: linq to entity framework: use dictionary in query

ASP Classic - Recordset Object vs. Command Object

I am using ASP Classic and SQL Server 2000 to create dynamic websites.
I am a bit confused about when to use a recordset object and when to use a command object when querying the database.
I was told that if the stored procedure would be returning records from a SELCT statement then I should use a recordset, however if I am up updating or inserting then I should use a command object and pass all data as parameters to the stored procedure.
When using a recordset I often pass any required data like so:
rs.Source = "spTest " & id
I alway validate the data that I am passing to make sure it is what I am expecting and cast it to its correct type.
I have since been told however that the above method leaves my code open to SQL Injection attacks and that I should always use a command object.
Is this correct?
Thanks
Yes, that's right.
Imagine someone passing the string: '0; delete * from users;'
You query would then be:
spTest 0; delete * from users;
If you're lucky you won't have a users table. Personally, I would use the command object all the time for consistency. You can get everything you need from it.
Here is a quick example of how you might do it with the command object:
Dim oStoredProc : Set oStoredProc = Server.CreateObject("ADODB.Command")
With oStoredProc
.ActiveConnection = oDBConnection
.CommandType = adCmdStoredProc
.CommandText = "up_procname"
.Parameters.Append(.CreateParameter("#Param1", ADODB.adInteger, ADODB.adParamInput, 22, 11))
.Parameters.Append(.CreateParameter("#Param2", ADODB.adInteger, ADODB.adParamOutput, 22, 12)
Call .Execute()
myVal = .Parameters("#Param2")
End With
Set oStoredProc = Nothing
What you were told is correct indeed : you should always use commande objects to prevent SQL Injection. Using parameterized queries, you leave all the security and validation of parameters to the ADO layer (though you should still do your own proper validation), and you may even get some performance improvement (these parameterized queries are cached by SQL Server)
When you execute a command you have two options : either the SQL you execute returns rows (A SELECT Statement, or some stored procedures), then you have to use a recordset to store these rows, either it doesn't (UPDATES, DELETES, other procedures), then you juste execute the command and do not worry about recordsets.
Edit : just to make sure everything is clear for you, I used James Wiseman's code above and adapted it to your example :
Dim oStoredProc : Set oStoredProc = Server.CreateObject("ADODB.Command")
With oStoredProc
.ActiveConnection = oDBConnection
.CommandType = adCmdStoredProc
.CommandText = "spTest ?"
.Parameters.Append(.CreateParameter("id", ADODB.adInteger, ADODB.adParamInput, id, 11))
Dim rs : Set rs = .Execute()
End With
Set oStoredProc = Nothing
Didn't test it, but should be ok :-)
Last but not least : even though you're pretty well protected now, don't forget that if you're using dynamic SQL inside your stored procedure you may still have an SQL Injection security hole (as soon as you're concatenating strings to create SQL you may be vulnerable I would say) !

Resources