How to generate nHibernate raw sql for Insert/Update without execution? - c#

Is it possible to generate a raw SQL statement for insert/update operations using nHibernate without actually executing them? Assuming of course that everything (mappings, connectionStrings, etc.) is properly configured?
The closest thing I've found is to call:
Session.SessionFactory.GetClassMetadata(typeof(Client))
Which returns an object of type SingleTableEntityPersister containing SQLIdentityInsertString, that looks like this:
INSERT INTO Client (FirstName, LastName) values (?, ?)
But it would still require me to bind all of the properties manually, and on top of that SQLIdentityInsertString is a protected property. Are there any proper ways of doing that?

Okay, the closest thing I've found is to construct your own sql query with a string builder. First you need to extract your class metadata:
var metaData = Session.SessionFactory.GetClassMetadata(typeof(Client)) as SingleTableEntityPersister;
Then you can retrieve other information, such as:
var propertyNames = metaData.PropertyNames;
var tableName = metaData.TableName;
var firstPropertyValue = metaData.GetPropertyValue(client, propertyNames[0], EntityMode.Poco);
Once you have that information you can construct your own query manually. Not exactly the solution I wanted, but it's as close as it gets, I think.
However, one thing to note is that Session.CreateSQLQuery(string) method is currently bugged, and as a result SetParameter method doesn't work with more than 10 named parameters. There already seems to be a bug report created for this on NHbiernate's Jira.

Related

What's the best way to organize SQL queries?

We have a couple of SQL queries as strings:
public class Query
{
public static string CreditTransferId(string expectedValue, string table, int statusId, int messageTypeId, int destination103, int destination202, string StoreStatus202Id)
{
return $"SELECT top 1 Id from {table} where MessageId = '{expectedValue}' and FlowId=3 and StatusId={statusId} and MessageTypeId={messageTypeId} and " +
$" Destination103={destination103} and Destination202={destination202} and StoreStatus103Id is null and StoreStatus202Id {StoreStatus202Id}";
}
}
We have them returned as strings from methods inside the Query class. We want to refactor the code, since we have a method with more than 3 parameters which is pretty hard to use.
How would you go about this? What's the cleanest way to organize SQL queries which need a lot of parameters?
Dynamic SQL is a very bad thing for a start as these are open to SQL injection, you should use parameterise queries and return a string.
"eg: SELECT top 1 Id from [Table] where [MessageId] = #messageId" etc
So you dont need to pass in any values, you would add these to your list of SqlParamater's
The table name is probably pointless as this is related to the sql, so probably just add that into the sql string
This doesn't really need an extra class, just create the sql variable where you call it, so it right there if you need it?
..or use Stored Procedures
..or use Entity Framework
EF is great and you have to decide if that's what you want. There are some cases where it is not suitable. Of u decide to stick with plain text queries how about dividing queries into parts:
FromBuilder
JoinBuilder
GroupBuilder
Condition builder etc
ex.:
return #"
"+new TableIdSelectorBuilder(table).Get() +#"
"+new FromBuilder().Get(table) +#"
"+new TableConditionByIdBuilder(table).Get(I'd)+#"
";
EDIT:
Stored procedures allow to change queries without publishing new app version but is a bit pain in the ass to work on a living organism. At least sometimes.
Hopefully this helps you a bit. I was figuring this out a long time ago too.
Use nameOf instead of hardcoded column names
One advice that I have is: Try to use nameOf() for column names (in case your domain model matches exactly your database structure).
Refactoring becomes a lot easier as well.
Create a query builder
I created a class which allows me to create simple to medium complex queries (Select, Insert, Update, Joins, Deletes, Limit, Offset, ...). For most of the queries that I write I can use this query builder to get what I need and the code will look something like this:
var query = new QueryBuilder()
.Update(nameof(MyTable))
.Set(nameof(MyTable.Name), entity.Name)
.Set(nameof(MyTable.Firstname), entity.Firstname)
.WhereEquals(nameof(MyTable.Id), entity.Id)
.Build();
Unfortunately, I haven't found a good QueryBuilder out there yet. Therefore I created my own.
Use string literals
Microsoft Documentation
Another solution that I recently encountered is by doing the following:
var query = $$"""
SELECT * FROM {{nameof(MyTable)}
WHERE
XX
""";
This at least allows you to indent correctly and the code will remain clean.
Outsource your queries in separate files
I was also thinking about having bigger queries in separate files and include them in the Assembly. When you want to execute the query, you load the query from the file and run it like this.
You might also want to cache that query then, to not always load it from the file.
Final words
Personally, I try to use the QueryBuilder as often as possible. It creates clean code which looks somewhat like LINQ
Backup approach for me is to use the string literals as showed above
Trying to create separate files for queries, I have never tried yet, because there was no use for myself
I would also avoid using Stored Procedures, because they are pain to write and also hard to debug in my opinion
The cleanest option would be to use Entity Framework, but if you want to use Micro-ORMs like Dapper, try one of the solutions above

lightswitch LINQ PreprocessQuery

I use the PreprocessQuery method to extend a query in lightswitch.
Something like this:
query = (from item in query
where (validIDs.Contains(item.tableIDs.myID)) &&
elementCount[item.ID] <= maxEleCount)
select item);
Where validIDs is a HashSet(int) and elementCount is a Dictionary(int, int).
the first where clause is working fine, but the second -> elementCount[item.ID] <= maxEleCount
is not working.
What i want to do is to filter a table by some IDs (validIDs) and check also if in another table the number of entries for every of this IDs does not exceed a limit.
Any ideas?
EDIT
I found a solution. Instead of a Dictionary I also used a HashSet for the second where clause. It seems it is not possible to do the Dictionary lookup inside the LINQ statement for some reason (?)
First, although being a bit pedantic, what you're doing in a PreProcessQuery method is "restricting" records in the query, not "extending" the query.
What you put in a LING query has to be able to be processed by the Entity Framework data provider (in the case of LS, the SQL Server Data Provider).
Sometimes you'll find that while your LINQ query compiles, it fails at runtime. This is because the data provider is unable to express it to the data store (again in this case SQL Server).
You're normally restricted to "primitive" values, so if you hadn't said that using a Dictionary actually worked, I would have said that it wouldn't.
Any time you have a static (as in non-changing) value, I'd suggest that you create a variable outside of your LINQ query, then use the variable in the LINQ query. By doing this, you're simply passing a value, the data provider doesn't have to try to figure out how to pass it to the data store.
Reading your code again, this might not be what you're doing, but hopefully this explanation will still be helpful.

Dynamic Object - Tidy property names?

I'm using some code to execute a SQL and return a IEnumerable of dynamic objects. The code is here if you want to see it.
I have a table with a column name such as APPLICATION_NAME;
In my object I have to reference it like so:
var results = ReturnResults("Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=rawdb;Data Source=mypc", "SELECT * FROM APPLICATIONS");
string name = results.First().APPLICATION_NAME;
Is there a way to make property names resolve to something tidier? ie.
string name = results.First().ApplicationName;
Thanks
There are some ToCamelCase() extensions out there (just google it). But if you would implement it into your dynamic object. How do you know which shiny name you have to take for an ugly column name?
Instead you should rewrite your select statement to return nice names, instead of implementing some algorithm into the dynamic object. How about this statement:
SELECT APPLICATION_NAME as 'ApplicationName' FROM APPLICATIONS
So it is clear to everyone who reads the sql statement how to access the columns through the dynamic object.

C# NHibernate Issue - Im trying to return Distinct values

C# NHibernate Issue - Im trying to return Distinct values.
This is what I have so far:
IList<TaskFor> objsResult = session.CreateCriteria(typeof(TaskFor)).setProjection(Projections.Distinct).List<TaskFor>();
return objsResult;
I am trying to return a group of values but I need to remove the duplicates.
I cant seem to get set projections to work properly for this instance.
Look forward to hearing any answers.
Thanks,
marc
I'd say this answer from Aidan Boyle could be very helpfull for you.
To perform a distinct query you can set the projection on the criteria to Projections.Distinct. You then include the columns that you wish to return. The result is then turned back into an strongly-typed object by setting the result transformer to AliasToBeanResultTransformer - passing in the type that the result should be transformed into. In this example I am using the same type as the entity itself but you could create another class specifically for this query.
ICriteria criteria = session.CreateCriteria(typeof(Person));
criteria.SetProjection(
Projections.Distinct(Projections.ProjectionList()
.Add(Projections.Alias(Projections.Property("FirstName"), "FirstName"))
.Add(Projections.Alias(Projections.Property("LastName"), "LastName"))));
criteria.SetResultTransformer(
new NHibernate.Transform.AliasToBeanResultTransformer(typeof(Person)));
IList people = criteria.List();
This creates SQL similar to (in SQL Server at least):
SELECT DISTINCT FirstName, LastName from Person
Please be aware that only the properties that you specify in your projection will be populated in the result.
The advantage of this method is that the filtering is performed in the database rather than returning all results to your application and then doing the filtering - which is the behaviour of DistinctRootEntityTransformer.

Dynamically Modifying a LINQ to SQL Select Statement's Columns

I'm trying to build a REST-ful API for my app. Currently I have something like this:
www.example.com/submissions/?format=json
This will return latest ten submissions in JSON. Each object has its details, such as submission name, date created, user, body, etc.
I'd like to do something such as:
www.example.com/submissions/?format=json&filter=name,user
The filter should make the request to return the same result but to only include the details mentioned, i.e. each object will only have a name and user.
This is fairly straightforward in terms of the JSON output. I can load all the columns from the database and create and serialize an object that will only include the columns in the filter. However, I do not want to load all the columns in the database - I want to bother my database with only the columns that I will include in the response.
I want to do something like this:
var result = from record in Submissions
select
{
Name,
Date,
User,
Body
};
Now I have the result object, which is IQueryable, so no call to database made yet.
Then, I should examine the filter querystring and exclude the columns that are not mentioned.
Finally, I can execute the select statement with something like
JavaScript.Serialize(result.ToList());
Is this possible with LINQ to SQL?
An alternative to building your Select expression tree by hand is Dynamic LINQ, which provides a Select method that takes a string:
var filter = "name,user";
var result = Submissions.Select("new(" + filter + ")");
The string is then translated into an expression tree and passed on to your query provider.
Yes. You are going to want to research Modifying Expression Trees. Specifically the MemberInit Expression.

Categories