Does anyone know how to convert NHibernate HQL to SQL Scripts?
Since HQL translation depends on your mappings and also runtime behaviour, I think it is unlikely there is a way to do so statically.
You could run the HQL against a real database and capture the generated SQL either via a profiler for your specific rdbms or NHProf.
My old trainings. That was beta-version. Here it is! (hql2sql.jsp)
<SCRIPT type="text/javascript">
<%
org.hibernate.Session ThisSession = SessionFactory.getSession();
org.hibernate.engine.SessionImplementor ThisSessionImplementor = (org.hibernate.engine.SessionImplementor) ThisSession;
org.hibernate.engine.SessionFactoryImplementor ThisSessionFactory = (org.hibernate.engine.SessionFactoryImplementor) ThisSession.getSessionFactory();
String HQL_Query = "SELECT ... ";
String SQL_Query;
try{
org.hibernate.engine.query.HQLQueryPlan HQL_Query_Plan = new org.hibernate.engine.query.HQLQueryPlan(HQL_Query, true, ThisSessionImplementor.getEnabledFilters(), ThisSessionFactory);
SQL_Query = org.apache.commons.lang.StringUtils.join(HQL_Query_Plan.getSqlStrings(), ";");
}catch(Exception e){SQL_Query = "ERROR!! :: " + e.getMessage();}
%>
$(document).ready(function(){
$('span[role="HQL"]').text(" <%=HQL_Query%>");
$('span[role="SQL"]').text(" <%=SQL_Query%>");
});
</SCRIPT>
<div style="border:2px solid brown">
Ваш запрос на HQL:
<br/><br/><span role="HQL"> </span>
</div>
<br>
<div style="border:2px solid green">
Ваш запрос на SQL:
<br/><br/><span role="SQL"> </span>
</div>
I'm not familiar with all the parameters, but this seems to work:
ISessionFactory sessionFactory = ...
var sf = (SessionFactoryImpl) sessionFactory;
var hql = "from Person";
var qt = sf.Settings.QueryTranslatorFactory.CreateQueryTranslator("", hql, new Dictionary<string, IFilter>(), (ISessionFactoryImplementor) sessionFactory);
qt.Compile(new Dictionary<string, string>(), true);
var sql = qt.SQLString;
Console.WriteLine(sql);
I'm not sure what the value of auto-converting HQL to SQL is dynamically...
What exactly are you trying to accomplish by this?
The easiest way would be to run your code while running SQL Server Profiler to see the generated SQL. But a better approach would be to download nhProf (www.nhprof.com) and use that with your code. You will be able to see exactly what your code is outputting in SQL and it will format and color code it and also give you tips on ways to improve your usage of nhibernate.
With NHibernate 3.2, this seems to be the easiest way to get the SQL from an HQL query:
private string GetSQL(string hql)
{
using (var iSession = ...)
{
var session = (NHibernate.Engine.ISessionImplementor)iSession;
var sf = (NHibernate.Engine.ISessionFactoryImplementor)iSession.SessionFactory;
var sql = new NHibernate.Engine.Query.HQLStringQueryPlan(hql, true, session.EnabledFilters, sf);
return string.Join(";", sql.SqlStrings);
}
}
Here is how to do it with NH 5.2 (see https://stackoverflow.com/a/55542462/2047306)
public static string HqlToSql(string hql, ISession session)
{
var sessionImp = (ISessionImplementor)session;
var translatorFactory = new ASTQueryTranslatorFactory();
var translators = translatorFactory.CreateQueryTranslators(new NHibernate.Hql.StringQueryExpression(hql),
null, false, sessionImp.EnabledFilters, sessionImp.Factory);
var hqlSqlGenerator = new HqlSqlGenerator(((QueryTranslatorImpl)translators[0]).SqlAST, sessionImp.Factory);
hqlSqlGenerator.Generate();
return hqlSqlGenerator.Sql.ToString();
}
Related
I am currently updating a BackEnd project to .NET Core and having performance issues with my Linq queries.
Main Queries:
var queryTexts = from text in _repositoryContext.Text
where text.KeyName.StartsWith("ApplicationSettings.")
where text.Sprache.Equals("*")
select text;
var queryDescriptions = from text in queryTexts
where text.KeyName.EndsWith("$Descr")
select text;
var queryNames = from text in queryTexts
where !(text.KeyName.EndsWith("$Descr"))
select text;
var queryDefaults = from defaults in _repositoryContext.ApplicationSettingsDefaults
where defaults.Value != "*"
select defaults;
After getting these IQueryables I run a foreach loop in another context to build my DTO model:
foreach (ApplicationSettings appl in _repositoryContext.ApplicationSettings)
{
var applDefaults = queryDefaults.Where(c => c.KeyName.Equals(appl.KeyName)).ToArray();
description = queryDescriptions.Where(d => d.KeyName.Equals("ApplicationSettings." + appl.KeyName + ".$Descr"))
.FirstOrDefault()?
.Text1 ?? "";
var name = queryNames.Where(n => n.KeyName.Equals("ApplicationSettings." + appl.KeyName)).FirstOrDefault()?.Text1 ?? "";
// Do some stuff with data and return DTO Model
}
In my old Project, this part had an execution from about 0,45 sec, by now I have about 5-6 sec..
I thought about using compiled queries but I recognized these don't support returning IEnumerable yet. Also I tried to avoid Contains() method. But it didn't improve performance anyway.
Could you take short look on my queries and maybe refactor or give some hints how to make one of the queries faster?
It is to note that _repositoryContext.Text has compared to other contexts the most entries (about 50 000), because of translations.
queryNames, queryDefaults, and queryDescriptions are all queries not collections. And you are running them in a loop. Try loading them outside of the loop.
eg: load queryNames to a dictionary:
var queryNames = from text in queryTexts
where !(text.KeyName.EndsWith("$Descr"))
select text;
var queryNamesByName = queryName.ToDictionary(n => n.KeyName);
one can write queries like below
var Profile="developer";
var LstUserName = alreadyUsed.Where(x => x.Profile==Profile).ToList();
you can also use "foreach" like below
lstUserNames.ForEach(x=>
{
//do your stuff
});
I know there is a few post about it. I've tryed to work with the answer but I must be missing something somewhere (I'm pretty noob).
As I said in the title, I would like to have a page that show a big list of item checked or not according to database information. The page load with an Id.
Type: CSHTML, Razor
Database: defect
Table name: defectqc
The table is looking a bit like that so far:
<table>
<tr><td><p><input type="checkbox" name="ltcheck1" checked="#ltcheck1"></td></tr>
<tr><td><p><input type="checkbox" name="ltcheck2" checked="#ltcheck2"></td></tr>
<tr><td><p><input type="checkbox" name="ltcheck3" checked="#ltcheck3"></td> </tr>
</table>
So the code script I've tryed at the begining is this one...
var Id = "";
var ltcheck1 = "";
var ltcheck2 = "";
var ltcheck3 = "";
if(!IsPost){
if(!Request.QueryString["Id"].IsEmpty() && Request.QueryString["Id"].IsInt()) {
Id = Request.QueryString["Id"];
var db = Database.Open("defect");
var dbCommand = "SELECT * FROM defectqc WHERE Id = #0";
var row = db.QuerySingle(dbCommand, Id);
if(row != null) {
ltcheck1 = row.ltcheck1;
ltcheck2 = row.ltcheck2;
ltcheck2 = row.ltcheck3;
}
The database got column written "True" or "False" into it. I want the checkboxes to be checked if the column is "true"
Please MTV! Pimp my ride! ;D
Sorry for my english, I'm trying hard
<input type="checkbox"/>
Will only be checked if you use the attribute
checked
or
checked="checked"
So try to generate this:
<input type="checkbox" checked/>
Following your logic Schaemelhout Would it be possible if I use this kind of statement
var Id = "";
var ltcheck1 = "";
var ltcheck2 = "";
var ltcheck3 = "";
if(!IsPost){
if(!Request.QueryString["Id"].IsEmpty() && Request.QueryString["Id"].IsInt()) {
Id = Request.QueryString["Id"];
var db = Database.Open("defect");
var dbCommand = "SELECT * FROM defectqc WHERE Id = #0";
var row = db.QuerySingle(dbCommand, Id);
if(row.ltcheck1 = "true") {
ltcheck1.checked
}
if(row.ltcheck2 = "true") {
ltcheck1.checked
}
(I know the syntax isn't correct)
I found this which is in PHP
<input type="checkbox" name="ltcheck1" value="True" <?php echo $checked; ?> />
if ($row['letcheck1'] == 'True') $checked = 'checked="checked"';
Assuming that the data have already been pulled out. It would do exactly what I need... Is there a way to translate it?
Why don't you use the html helpers?
#Html.CheckBox("ltcheck1")
#Html.CheckBox("ltcheck2")
#Html.CheckBox("ltcheck3")
I have a linq object and I want to write the query using linq.
please help me.
INPUT:
var tags = (from row in tempChildData.AsEnumerable()
join tagOrder in tupleInfoDataset.Tables["TagHierarchy"].AsEnumerable() on row.Field<Int64>("TAGID") equals tagOrder.Field<Int64>("TAGID")
join tagName in tupleInfoDataset.Tables["SequenceChoiceList"].AsEnumerable() on tagOrder.Field<Int64>("PARENTTAGID") equals tagName.Field<Int64>("TAGID")
join facet in tupleInfoDataset.Tables["FacetType"].AsEnumerable() on tagName.Field<string>("Tag_Name") equals facet.Field<string>("Facetname")
join tagIdInfo in schDataTogetTagid.AsEnumerable() on row.Field<string>("refTagName").Contains(":") ? row.Field<string>("refTagName").Split(':').Last():row.Field<string>("refTagName") equals tagIdInfo.Field<string>("TAGNAME")
where ( childList.Contains(row.Field<Int64>("TAGID")) && facet.Field<string>("FacetType").ToLower().Equals("ctype"))
select new
{
Tagid = row.Field<Int64>("TAGID"),
TagIdToInsert=tagIdInfo.Field<Int64>("TAGID"),
MaxOccur = row.Field<string>("Maxoccurs"),
MinOccur =Convert.ToInt32(Convert.ToString(row.Field<string>("Minoccur"))),
ParentTagId=tagOrder.Field<Int64>("PARENTTAGID"),
Order=tagOrder.Field<Int64>("TAG_ORDER"),
ParentTagname = tagName.Field<string>("Tag_Name"),
FacetId=facet.Field<Int64>("FacetID")
}).ToList();
var parentTagID = (from tagIdInfo in tupleInfoDataset.Tables["Tuple"].AsEnumerable()
where tagIdInfo.Field<Int64>("TAGID").Equals(key.Key)
select tagIdInfo.Field<Int64>("ConceptID")).ToList();
long parentID =Convert.ToInt64(parentTagID[0]);
Now i want the query out of the above code as:
INSERT INTO TUPLE_MAP (TagId,ParentTagId,ParentTagname,MinOccur,MaxOccur,Order)
VALUES (TagIdToInsert,ParentTagId,ParentTagname,MinOccur,MaxOccur,Order)
Please help me I don't know how to write SQL queries using linq
Maybe something like this:
using(var db=new DataContext("YourConnectionStringHERE"))
{
db.TUPLE_MAP.InsertAllOnSubmit(tags.Select (t =>
new TUPLE_MAP()
{
TagId=t.TagIdToInsert,
ParentTagId=t.ParentTagId,
ParentTagname=t.ParentTagname,
MinOccur=t.MinOccur,
MaxOccur=t.MaxOccur,
Order=t.Order
}));
db.SubmitChanges();
}
Or if you want to use the parentID then something like this:
using(var db=new DataContext("YourConnectionStringHERE"))
{
db.TUPLE_MAP.InsertAllOnSubmit(tags.Select (t =>
new TUPLE_MAP()
{
TagId=t.TagIdToInsert,
ParentTagId=parentID,
ParentTagname=t.ParentTagname,
MinOccur=t.MinOccur,
MaxOccur=t.MaxOccur,
Order=t.Order
}));
db.SubmitChanges();
}
where db is your linq data context
Useful references:
How to: Insert Rows Into the Database (LINQ to SQL)
EDIT
So if you are using the Compact database 3.5 then many something like this:
using (var conn =new SqlCeConnection("Data Source = test.sdf; Password ='pass'"))
{
foreach (var tag in tags)
{
using(var cmd = conn.CreateCommand())
{
cmd.CommandText = #"INSERT INTO TUPLE_MAP (TagId,ParentTagId,ParentTagname,MinOccur,MaxOccur,Order)
VALUES (#TagIdToInsert,#ParentTagId,#ParentTagname,#MinOccur,#MaxOccur,#Order)";
cmd.Parameters.AddWithValue("#TagIdToInsert", tag.TagIdToInsert);
cmd.Parameters.AddWithValue("#ParentTagId", tag.ParentTagId);
cmd.Parameters.AddWithValue("#ParentTagname", tag.ParentTagname);
cmd.Parameters.AddWithValue("#MinOccur", tag.MinOccur);
cmd.Parameters.AddWithValue("#MaxOccur", tag.MaxOccur);
cmd.Parameters.AddWithValue("#Order", tag.Order);
cmd.ExecuteNonQuery();
}
}
}
Useful references:
Why can't I insert a record into my SQL Compact 3.5 database?
SqlCeCommand.Parameters Property
SqlCeCommand Class
SqlParameterCollection.AddWithValue Method
Use linq Pad or sql profiler to see the generated SQL.
You can also use visual studio for that purpose. In the debug mode,hold cursor on the variable "tags", you will be able to see the SQL.
I am assuming you are using Linq to SQL, if you are doing so you would have entity called Tuple_map in you xxxDataContext. Then you would just have to create object of that entity something like this....
using (XXXDataContext context = new XXXDataContext())
{
Tuple_map obj = new Tuple_map();
//Populate obj properties like obj.tabid = from objects you got it from above query
context.Tuple_map.InsertOnSubmit(obj);
context.SubmitChanges();
}
Using Dapper-dot-net...
The following yields no results in the data object:
var data = conn.Query(#"
select top 25
Term as Label,
Type,
ID
from SearchTerms
WHERE Term like '%#T%'",
new { T = (string)term });
However, when I just use a regular String Format like:
string QueryString = String.Format("select top 25 Term as Label, Type, ID from SearchTerms WHERE Term like '%{0}%'", term);
var data = conn.Query(QueryString);
I get 25 rows back in the collection. Is Dapper not correctly parsing the end of the parameter #T?
Try:
term = "whateverterm";
var encodeForLike = term => term.Replace("[", "[[]").Replace("%", "[%]");
string term = "%" + encodeForLike(term) + "%";
var data = conn.Query(#"
select top 25
Term as Label,
Type,
ID
from SearchTerms
WHERE Term like #term",
new { term });
There is nothing special about like operators, you never want your params inside string literals, they will not work, instead they will be interpreted as a string.
note
The hard-coded example in your second snippet is strongly discouraged, besides being a huge problem with sql injection, it can cause dapper to leak.
caveat
Any like match that is leading with a wildcard is not SARGable, which means it is slow and will require an index scan.
Yes it does. This simple solution has worked for me everytime:
db.Query<Remitente>("SELECT *
FROM Remitentes
WHERE Nombre LIKE #n", new { n = "%" + nombre + "%" })
.ToList();
Best way to use this to add concat function in query as it save in sql injecting as well, but concat function is only support above than sql 2012
string query = "SELECT * from country WHERE Name LIKE CONCAT('%',#name,'%');"
var results = connection.query<country>(query, new {name});
The answer from Sam wasn't working for me so after some testing I came up with using the SQLite CONCAT equivalent which seems to work:
string sql = "SELECT * FROM myTable WHERE Name LIKE '%' || #NAME || '%'";
var data = IEnumerable data = conn.Query(sql, new { NAME = Name });
Just to digress on Sam's answer, here is how I created two helper methods to make searches a bit easier using the LIKE operator.
First, creating a method for generating a parameterized query, this method uses dynamic: , but creating a strongly typed generic method should be more desired in many cases where you want static typing instead of dynamic.
public static dynamic ParameterizedQuery(this IDbConnection connection, string sql, Dictionary<string, object> parametersDictionary)
{
if (string.IsNullOrEmpty(sql))
{
return null;
}
string missingParameters = string.Empty;
foreach (var item in parametersDictionary)
{
if (!sql.Contains(item.Key))
{
missingParameters += $"Missing parameter: {item.Key}";
}
}
if (!string.IsNullOrEmpty(missingParameters))
{
throw new ArgumentException($"Parameterized query failed. {missingParameters}");
}
var parameters = new DynamicParameters(parametersDictionary);
return connection.Query(sql, parameters);
}
Then adding a method to create a Like search term that will work with Dapper.
public static string Like(string searchTerm)
{
if (string.IsNullOrEmpty(searchTerm))
{
return null;
}
Func<string, string> encodeForLike = searchTerm => searchTerm.Replace("[", "[[]").Replace("%", "[%]");
return $"%{encodeForLike(searchTerm)}%";
}
Example usage:
var sql = $"select * from products where ProductName like #ProdName";
var herringsInNorthwindDb = connection.ParameterizedQuery(sql, new Dictionary<string, object> { { "#ProdName", Like("sild") } });
foreach (var herring in herringsInNorthwindDb)
{
Console.WriteLine($"{herring.ProductName}");
}
And we get our sample data from Northwind DB:
I like this approach, since we get helper extension methods to do repetitive work.
My solution simple to this problem :
parameter.Add("#nomeCliente", dfNomeCliPesquisa.Text.ToUpper());
query = "SELECT * FROM cadastrocliente WHERE upper(nome) LIKE " + "'%" + dfNomeCliPesquisa.Text.ToUpper() + "%'";
I´m using the LinqDataSource to populate a grid. But now I need the SQL query that the LinqDataSource generates, to pass around throught methods (no, I can't modify the methods to not need a SQL query).
Is there a way to obtain the generated SQL query from a instantiated and configured LinqDataSource?
Hope this helps.
using the function below will return a SqlQueryText
you can rebuild the query from that object.
to get the sql text you can use use the .Text Property
to get the passed
parameters you can use the .Params property
public static SqlQueryText GetFullQueryInfo(DataContext dataContext, IQueryable query)
{
DbCommand dbCommand = dataContext.GetCommand(query);
var result = new SqlQueryText();
result.Text = dbCommand.CommandText;
int nParams = dbCommand.Parameters.Count;
result.Params = new ParameterText[nParams];
for (int j = 0; j < nParams; j++)
{
var param = new ParameterText();
DbParameter pInfo = dbCommand.Parameters[j];
param.Name = pInfo.ParameterName;
param.SqlType = pInfo.DbType.ToString();
object paramValue = pInfo.Value;
if (paramValue == null)
{
param.Value = null;
}
else
{
param.Value = pInfo.Value.ToString();
}
result.Params[j] = param;
}
return result;
}
here is an example
var results = db.Medias.Where(somepredicatehere);
ClassThatHasThisMethod.GetFullQueryInfo(yourdatacontexthere, results);
EDIT:
Sorry forgot to include the SqlQueryText data structures
public struct SqlQueryText
{
public ParameterText[] Params;
public string Text;
}
public struct ParameterText
{
public string Name;
public string SqlType;
public string Value;
}
You can run SQL Profiler while running your application and that should give it to you.
Take a look at LinqPad for debugging and to understand how it works. But if you want it at run-time, I think you're out of luck.
The Sql will only be generated by the Linq to Sql infrastructure at runtime.
I think there are some tools to see generated Sql in the debugger, but if you don't plan to use linq to generate your Sql dynamicaly, shouldn't you probably look for a simple Sql designer ?
I Found a Linq To Sql Debug visualizer on Scottgu's blog.