Using in-built sql "Convert" function in nhibernate criteria - c#

I want to make use of the Convert function in SQL Server 2008 so I can search on a DateTime column.
The proposed SQL would look something like this:
SELECT (list of fields) FROM aTable
WHERE CONVERT(VARCHAR(25), theColumn) LIKE '%2009%'
Here is part of the criteria that tries to emulate the call to convert:
Projections.SqlFunction("CONVERT",
NHibernateUtil.String,
Projections.Constant("varchar(25)"),
Projections.Property(searchCol))
The search column would be dynamically selected so it cannot be hard coded in a query.
The problem is that when the SQL is generated by nhibernate, its passing in the data type as a string, when there shouldn't be any quotes around it.
So the generated sql looks like:
(convert(#p3, this_.theColumn) LIKE #p4
When it needs to be:
(convert(varchar(25), this_.theColumn) LIKE #p4
I am definitely sure the problem is with Projections.Constant("varchar(25)") but I do not know the correct projections syntax to make it work.

If you could accept the CAST instead of CONVERT (And I am almost sure that you can), then there is more straightforward solution.
Instead of calling "SQL Server related" function, let's call the abstraction, which should be working on most DB Servers (based on supported NHibernate dilacts)
Projections.Cast(NHibernateUtil.String, Projections.Property(searchCol))
So the Restriction used in a WHERE clause could look like this:
Restrictions
.Like (
Projections.Cast(NHibernateUtil.String, Projections.Property(searchCol))
, "2009"
, MatchMode.Anywhere
)
And the result generated by NHibernate, using the SQL Server dialect would be:
WHERE cast( this_.theColumn as NVARCHAR(255)) like #p1 ... #p1=N'%2009%'

Related

How to INSERT multiple Values using Parameters WITHOUT declaring a SQL Server Type?

Like the title says, I'm trying to insert multiple values into SQL Server using an INSERT command dynamically constructed in code.
The command looks like this:
INSERT INTO xLog (value1, value2, value3)
VALUES (#xLog);
And, following multiple other answers in this site, the parameter #xLog is an array of SqlDataRecord that contains the collection of values to insert (I have also followed the DataTable approach that was also suggested, with the same result as below).
But, when I try to execute this command, I get this error:
The table type parameter '#xLog' must have a valid type name.
...which I understand occurs because SQL Server is expecting a custom type to be created in the database that follows the parameter's structure. Let's say that I would prefer NOT to have create this custom type for X reason.
So the question is: is there a way to insert multiple rows into SQL Server, with parameters, from .net code, without using custom types OR stored procedures?
Thank you for your time.
Note to mods: I tagged with both vb.net and c# tags because I can use code in both languages. Thanks.
You can either use SqlBulkCopy (possibly in combination with a temp table), or pass a JSON or XML document and shred it in TSQL.

LINQ to SQL will not generate sargable query

I'm using LINQ To Sql (not Entity Framework), the System.Data.Linq.DataContext library, hitting a SQL Server 2005 database and using .Net Framework 4.
The table dbo.Dogs has a column "Active" of type CHAR(1) NULL. If I was writing straight SQL the query would be:
SELECT * FROM dbo.Dogs where Active = 'A';
The LINQ query is this:
from d in myDataContext.Dogs where d.Active == 'A' select d;
The SQL that gets generated from the above LINQ query converts the Active field to UNICODE. This means I cannot use the index on the dbo.Dogs.Active column, slowing the query significantly:
SELECT [t0].Name, [t0].Active
FROM [dbo].[Dog] AS [t0]
WHERE UNICODE([t0].[Active]) = #p1
Is there anything I can do to stop Linq to Sql from inserting that UNICODE() call (and thus losing the benefit of my index on dogs.Active)? I tried wrapping the parameters using the EntityFunctions.AsNonUnicode() method, but that did no good (it inserted a CONVERT() to NVARCHAR instead of UNICODE() in the generated sql), eg:
...where d.Active.ToString() == EntityFunctions.AsNonUnicode('A'.ToString());
Linq is meant to make it easier to write queries and does not always generate optimal SQL. Sometimes when high performance is required it is more efficient to write raw SQL directly against the database, the Linq datacontext supports mapping of SQL result to entities just like linq.
In your case I would suggest writing:
IEnumerable<Dog> results = db.ExecuteQuery<Dog>(
"SELECT * FROM dbo.Dogs where Active = {0}",
'A');
This is an old question, but I bumped into this recently.
Instead of writing
from d in myDataContext.Dogs where d.Active == 'A' select d;
Write
from d in myDataContext.Dogs where d.Active.Equals('A') select d;
This will produce the desired SQL without having to resort to any of the "hacks" mentioned in other answers. I can't say why for certain.
I've posted that as a question, so we'll see if we get any good answers.
There's not much you can do to the way LINQ queries are translated into SQL statements, but you can write a stored procedure that contains your queries and call that SP as a LINQ2SQL function. This way you should get full benefit of SQL Server optimizaions
You can do a little hack (as it is often required with LINQ to SQL and EF). Declare the property as NCHAR in the dbml. I hope that will remove the need to do the UNICODE conversion. We are tricking L2S in a benign way with that.
Maybe you need to also insert the EntityFunctions.AsNonUnicode call to make the right hand side a non-unicode type.
You can also try mapping the column as varchar.

What's the best practice in executing a stored procedure with multiple parameters using MVC3?

I am working at implementing a search feature into my MVC3 application. I'm looking to pass two parameters into and execute a stored procedure that will look basically something like this:
create procedure MyProc
(
#FirstParam nvarchar(50),
#SecondParam nvarchar(20)
)
as select * from MyTable where #FirstParam like #SecondParam
MyTable has about 30 fields that will be returned for each object and I need to create a procedure like this for several tables, so I am trying to avoid using a SqlDataReader and converting the returned Sql data to C#.
I would like to use something like this method but I am not sure if this can be done with multiple parameters.
Ideally I would like to use EF4, but I have not found any good information on executing stored procedures while using EF4.
Any insight on the most painless way and/or best practice for executing this task will be greatly appreciated.
My sugestion is use dynamic linq (and here, and here). You can pass valid linq expressions as regular strings:
var column = "Name";
var value = "Marvin";
var query = DbCtx.MyEntity.Where("{0} == #1", columnName, value);
The benefits (IMO) is that you can keep the search logic in the application and, if you need to do this for many tables, you can create a T4 template to generate the bootstrap code for you.
What you are suggesting can indeed be done through parameters, and you should be using an ORM like EF4 for you data access. Like most ORM that have support for stored procedure, you can indeed pass multiple parameters to the stored procedure.
The issue you will find, however, is that you can't have dynamic column names in SQL Server (or any other SQL database that I am aware of) - you can't give a column name in a variable.
You will need to use dynamic SQL to achieve this, either within the stored procedure or otherwise.

Using SQLite ADO.Net Provider Need to Put GUID Directly Into Query's Where Clause Without Use of a Parameter

Is there anyway to just have the GUID be part of the SQL Query itself without using a parameter?
Let me explain exactly what I am trying to do and why. I am working with an existing application that uses an ADO.Net to create and connect to a SQLite database. The current structure of the database and the method for querying it are horrendous. I am in the midst of a redesign of how it works fundamentally. However, that is not something that can be accomplished quickly. While that redesign is being completed, I have a situation that needs a band-aid solution. As a heads up, the reasoning behind the initial implementation of the code is obscure and appears to have been built by someone who had little database knowledge. Refactoring the entire database to not need this situation is the ultimate solution, but for now I'm just looking to work within the existing structure.
The design of the database relies on GUID's to uniquely identify rows. To perform filtered retrieval of the data the system dynamically builds a command that has an IN clause listing the GUIDs that should be retrieved. Right now the GUIDs are inserted into the query by using a parameter with type GUID, so the query will look like
SELECT * FROM data_table WHERE guid_col IN( ?, ?, ?, ?)
The problem comes in when I need to retrieve a relatively large amount of information. SQLite has a limitation of a 1000 parameters in a single query. If I need to pass in more than a 1000 GUIDs for the retrieval the query will just break. When building the above string it loops over a list of GUID's to insert the question marks and create the paramters. My band-aid fix to the problem was going to be to have the GUID value directly inserted into where the question marks are currently and forego having parameters in the query. After all, its kind of using parameters for a purpose they don't need to be used for.
The problem with this 'solution' is that I can't seem to get the GUID to match the data in the column i.e. the query is always returning null. I understand that GUIDs are not a native type to SQLite and underneath it is actually being represented as a BLOB (yes I am sure we are using the BLOB and not the string representation). Yet, I've been unable to get the query to execute correctly.
I've tried all the following so far:
I've tried calling ToString() on the GUID so the query looks like
SELECT * FROM data_table WHERE guid_col IN
( 'b5080d4e-37c3-4286-9c3a-413e8c367f36', 'aa0ff789-3ce9-4552-9840-5ed4d73c1e2c')
I've tried calling ToString("N") on the GUID so the query looks like
SELECT * FROM data_table WHERE guid_col IN
( 'b5080d4e37c342869c3a413e8c367f36', 'aa0ff7893ce9455298405ed4d73c1e2c')
I've tried calling ToString("B") on the GUID so the query looks like
SELECT * FROM data_table WHERE guid_col IN
( '{b5080d4e-37c3-4286-9c3a-413e8c367f36}',
'{aa0ff789-3ce9-4552-9840-5ed4d73c1e2c}')
I've tried calling ToByteArray() on the GUID and putting the result into the query by adding each byte to the string calling ToString("X") on each byte so the query looks like
SELECT * FROM data_table WHERE guid_col IN
( '4ED8B5C33786429C3A413E8C367F36', '89F7FAAE93C524598405ED4D73C1E2C')
In reading the SQLite documentation I read the following "BLOB literals are string literals containing hexadecimal data and preceded by a single "x" or "X" character. If I try to apply this to my query so it looks like
SELECT * FROM data_table WHERE guid_col IN
( x'4ED8B5C33786429C3A413E8C367F36', x'89F7FAAE93C524598405ED4D73C1E2C')
I get an error saying that "x" is not a recognized symbol.
Is it possible to get the GUID into the query string without the use of the parameter?
I suggest that you use a temporary table for something like this. For example...
PRAGMA temp_store = MEMORY;
CREATE TEMP TABLE tbl_guids (guid_col text);
INSERT INTO tbl_guids VALUES ('b5080d4e-37c3-4286-9c3a-413e8c367f36');
INSERT INTO tbl_guids VALUES ('aa0ff789-3ce9-4552-9840-5ed4d73c1e2c');
... more inserts ...
SELECT * FROM data_table WHERE guid_col IN ( SELECT guid_col FROM tbl_guids);
DROP TABLE tbl_guids;
Make sure to wrap a transaction around all of the INSERT INTO statements. This will help with performance by a ton. Also SQLite allows for temp tables to exist entirely in memory by setting PRAGMA temp_store = MEMORY
If you have a multiple users accessing the table at the same time sharing the same connection, you will need to create some uniqueness with the temp table such as adding a random number to the table name such as tbl_guids_9087.
You can pass GUID's in as strings if you set "BinaryGuid=False" in the connection string.
If this is done, "ToString()" should work fine.

SQL Server: way to see final query with filled parameters

Is there a way to see final query which is passed to SQL Server database from my C# app ?
For ex I got query:
SELECT * FROM mytable WHERE x = #yyyy;
This creates and SQLCommand object
SqlCommand cmd = new SqlCommand("SELECT * FROM mytable WHERE x = #yyyy");
Plus I need to pass parameter:
cmd.Parameters.Add("#yyyy","MyValue");
What I want to see (in debug in C# or somewhere in SQL Server Management Studio) is this:
SELECT * FROM mytable WHERE x = MyValue
Where can I find such query ?!
Best regards
Where can I find such query ?!
You can't. Such a query never exists. The values are not substituted into the SQL.
I think actually sp_executesql is called, and this function accepts the parameters separately from the SQL. You can check this using SQL Profiler to see the actual SQL.
Update:
ORDER BY #descOrAsc
Your problem is that parameters can only be used in certain places where expressions are allowed. DESC is not an expression - it is a reserved word. You cannot use a parameter containing the string "DESC" instead of writing the keyword DESC in the query.
Also, you haven't specified which column to order by.
You can run the SQL Server Profiler and see all the queries that get executed, to see whats happening (and copy paste these into the Sql Server Management Studio to do tests etc)
I would expect the query to be passed to SQL Server with the parameters. There should be no need for anything to ever create a full SQL-only query. It makes no sense to do so, as it just means more conversions for either the client, the server or both. On the server side, the query processor is going to want to parse the query into clauses with values - if the command can pass those values directly, where's the advantage on converting them into the SQL statement, only to have the server parse them into separate values again?
1.You can use SQL Profiler. (here you can see all process)
2.You can write all your queries to SQL Server table. And then you can always get queries from this table.

Categories

Resources