Get raw sql string in Sql Kata - c#

I am using SqlKata purely to build sql queries in C#. I am wanting to take the output of my built up Query, get the raw (compiled) sql string, and execute it against SQL.
I thought this would do it:
var factory = new QueryFactory(null, new SqlServerCompiler());
var query = new Query();
...
var sqlText = factory.Compiler.Compile(query).Sql;
But this gives this:
SELECT TOP (#p0) [AllStarFull].[GameNumber], [AllStarFull].[LeagueId], [AllStarFull].[PlayedInGame] FROM [AllStarFull]
This throws an exception because (#p0) is a param, and not the actual value.
In the documentation, it mentions to bring in Logger but I don't really need logging functionality (right now).
https://sqlkata.com/docs/execution/logging
var db = new QueryFactory(connection, new SqlServerCompiler());
// Log the compiled query to the console
db.Logger = compiled => {
Console.WriteLine(compiled.ToString());
};
var users = db.Query("Users").Get();
Is there anyway to get the raw sql string from the Query with all params populated?

If you need just to build the SQL there is no need to include the SqlKata.Execution package (which is include the QueryFactory class).
The simplest way is:
using SqlKata;
using SqlKata.Compilers;
// Create an instance of SQLServer
var compiler = new SqlServerCompiler();
var query = new Query("Users").Where("Id", 1).Where("Status", "Active");
SqlResult result = compiler.Compile(query);
string sql = result.Sql;
List<object> bindings = result.Bindings; // [ 1, "Active" ]
as mentioned in the docs you can use the result.ToString() to get the full query
var sql = result.ToString();
but this is not a good practice, the correct way is to use the parameterized query with bindings to execute it.
taken from https://sqlkata.com/docs#compile-only-example

If you are injecting QueryFactory dependency, you can use its compiler:
var query = new Query("Users")... etc
var rawSQL = queryFactory.Compiler.Compile(query).RawSql;

Related

Parameterized Where IN clause does not work with CosmosClient QueryDefinition Object

I am trying to write a parameterized query that has IN clause.
For Ex :
Working code
Input string : "'guid1','guid2','guid3'"
public List<Employee> GetEmployeeIds(string ids){
QueryDefinition query =new QueryDefinition(#"Select * from Employee where Employee.Id in ("+ ids+")");
var result = GetDetails(query,cosmosClient);
return result;
}
Result: It returns the expected result
Non-working code
Input string : "'guid1','guid2','guid3'"
public List<Employee> GetEmployeeIds(string ids){
QueryDefinition query =new QueryDefinition(#"Select * from Employee where Employee.Id in ( #ids )")
.WithParameter("#ids", ids);
var result = GetDetails(query,cosmosClient);
return result;
}
Result: It returns 0
NuGet package used for above code: Microsoft.Azure.Cosmos 3.8.0
Note: I have tried all the options which are mentioned in this link but it does not work with CosmosClient QueryDefinition Object
WHERE IN with Azure DocumentDB (CosmosDB) .Net SDK
Any help on this is highly appreciated.
Thanks in advance.!!
I'm guessing that your ids value is something like "12,42,94,7". As a string parameter #ids, the expression in (#ids) is broadly the same as in ('12,42,94,7'), which won't match any values, if the values are the individual numbers 12, 42, 94 and 7. When you used the simple contatenated version, the meaning was different - i.e. in (12,42,94,7) (note the lack of quotes), which is 4 integer values, not 1 string value.
Basically: when parameterizing this, you would need to either
use multiple parameters, one per value, i.e. ending up with in (#ids0, #ids1, #ids2, #ids3) with 4 parameter values (either by splitting the string in the C# code, or using a different parameter type - perhaps params int[] ids)
use a function like the STRING_SPLIT SQL Server function, if similar exists for CosmosDB - i.e. in (select value from STRING_SPLIT(#ids,','))
This is working for me, where #ids is an array type:
List<long> ids = new List<long>();
ids.Add(712300002201);
ids.Add(712300002234);
string querySql = #"Select * from Employee where ARRAY_CONTAINS(#ids, Employee.Id )";
QueryDefinition definition = new QueryDefinition(query).WithParameter("#ids", ids);
Have you tried looking into the question asked below.
Azure Cosmos DB SQL API QueryDefinition multiple parameters for WHERE IN
I think ids are being treated as a single string therefore the results are not returning.
Alternatively, you could try using Microsoft.Azure.DocumentDB.Core package and make use of Document Client to write LINQ queries like in the code snippet below.
using (var client = new DocumentClient(new Uri(CosmosDbEndpoint), PrimaryKeyCosmosDB)){
List<MyClass> obj= client.CreateDocumentQuery<List<MyClass>>(UriFactory.CreateDocumentCollectionUri(databaseName, collectionName))
.Where(r => ids.Contains(r.id))
.AsEnumerable();}

Teradata Query Using Dapper C#

I am trying to dynamically query a Teradata database using Dapper but am having some issues. Here is the code:
// model variable is the parameter passed in with search information
using (IDbConnection con = new TdConnection(connection.GetConnectionString()))
{
var builder = new SqlBuilder();
var selector = builder.AddTemplate($"SELECT * FROM Temp_Table /**where**/");
if (model.Id != 0)
{
builder.Where("Id = ?", new { model.Id });
}
if (!string.IsNullOrEmpty(model.Employee_Id))
{
builder.Where("Employee_Id = ?", new { model.Employee_Id });
}
var data= con.Query<TableModel>(selector.RawSql, model).ToList();
return data;
}
The error I am getting is:
[Teradata Database] [3939] There is a mismatch between the number of
parameters specified and the number of parameters required.
I have used very similar code to query DB2 which worked just fine; what do I need to do differently with Teradata?
Managed to figure it out. Changed the line for getting the data to:
var data= con.Query<TableModel>(selector.RawSql, selector.Parameters).ToList();
Not sure why passing in the model worked just fine in my DB2 version but not this Teradata version.
At first glance it appears to be falling through and not adding any "where" condition. Try to structure it in such a way that if it falls through then add 1=1 or a Teradata equivalent if that doesn't work.
I'm unfamiliar with the SqlBuilder() class; but if you have a way of seeing if there aren't any Where constraints added, then to add a generic one. Or, a dirtier way would be to keep a bool reference and check at the end.
Update
Try passing in the parameters:
var data= con.Query<TableModel>(selector.RawSql, selector.Parameters).ToList();

How do I query MongoDB using the C# driver with a query in string format?

I need to query MongoDB with a standard query like the following:
{"$and":[{"Name":"Accelero JKT M Tun XL "}]}
I typically build queries using the Query object in C# and then do something like this:
MongoCollection<BsonDocument> col = _database.GetCollection<BsonDocument>("SourceItem");
var query = Query.And(Query.EQ("AccountID", BsonValue.Create(Convert.ToInt32(_accountID))), Query.EQ("SKU", sku));
var docs = col.Find(query);
Since I already have the query, I do not want to use the Query object to build a query. How do I simply use the query that I already have?
There is a slightly simpler way to do this (you should just replace " with '):
var el = BsonDocument.Parse("{'$and':[{'Name':'Accelero JKT M Tun XL '}]}");
var doc = new QueryDocument(el);
var result = coll.Find(doc);

Dynamic Parameterized query with dapper

I want to write a query with a dynamic list of parameters (depending on parameter is set or not).
I want to execute the query on an oracle database using dapper.
Sample code:
var sqlParams = new List<object>();
var sqlBuilder = new StringBuilder();
sqlBuilder.Append("SELECT * FROM EXAMPLE WHERE 1 = 1 ");
if (!string.IsNullOrEmpty(aParam))
{
sqlBuilder.Append(" AND A LIKE ?");
}
if (!string.IsNullOrEmpty(bParam))
{
sqlBuilder.Append(" AND B LIKE ? ");
}
var sql = sqlBuilder.ToString();
return this.Connection.Query<Equipment>(
sql,
new { aParam, bParam } // ??
).ToList();
Dapper only really works with named parameters. I seem to recall that in oracle they are colon-prefixed, so:
if (!string.IsNullOrEmpty(aParam))
{
sqlBuilder.Append(" AND A LIKE :aParam");
}
if (!string.IsNullOrEmpty(bParam))
{
sqlBuilder.Append(" AND B LIKE :bParam");
}
Now your existing code here:
return this.Connection.Query<Equipment>(
sql,
new { aParam, bParam }
).ToList();
should work. Dapper uses the names of the members of the anonymous type as parameter names. It additionally includes some very basic code to check whether any given member does not exist in the sql, so if your sql only mentions :bParam, it won't actually add the aParam value as a parameter.
In more complicated scenarios, there is also a DynamicParameters object you can use, that functions more like a dictionary - but you don't need that here.

How do I get SQL statement from LinqToEntities clause

I have an issue that's causing me a lot of headache. I've already googled a solution some days ago, but I didn't found it yet, if one of you guys could help me, it would be great!
I have this method to take the SQL statement for me:
private static string GetClause<T>(IQueryable<T> clause) where T : BaseEntity
{
string snippet = "FROM [dbo].[";
string sql = clause.ToString();
string sqlFirstPart = sql.Substring(sql.IndexOf(snippet));
sqlFirstPart = sqlFirstPart.Replace("AS [Extent1]", "");
sqlFirstPart = sqlFirstPart.Replace("[Extent1].", "");
return sqlFirstPart;
}
But this doesn't work when I try to use some filter (e.g. where), cause it returns me some ""#p_linq_{0}"." instead of the values. I know these are the parameters of my query, but where are they stored?
I use this for batch delete purposes on the EF5 Code First.
If you create a query with a param like this:
var name = "xxx";
var query = ctx.Persons.Where(x => x.FirstName == name);
Then you can get the sql statement and parameters like this:
var oq = ((ObjectQuery<Person>)query);
var trace = oq.ToTraceString();
var p = oq.Parameters;
Use the param name "p_linq_{0}" without the # as an index on p, p["p_linq_{0}"].

Categories

Resources