using COLLATE in Linq to SQL - c#

I need to add Collation into ORDER BY clause. In other words, need to create IQueryable which will be interpteted something like:
SELECT column FROM table
ORDER BY [column] COLLATE *AnyCollation* DESC
Is it possible?

As far as I know you cannot change the collation using the LINQ. However there are some workarounds like creating a function in SQL Server and changing the collation there and then using it your code.
Here is a related thread which you can refer: Using collation in Linq to Sql

Related

Text search like SQL COLLATE Latin1_General_CI_AI with LINQ

I can search customers table without any problems by SQL.
select Name
from Customers
where Name COLLATE Latin1_General_CI_AI like '%ozgur%'
This query can find "özgür"
When I place this table to cache and try to search this table with linq, I can't find "özgür" by "ozgur" search word.
Is there any similar way to use Latin1_General_CI_AI in C# LINQ?
The only place I've found that uses a collation is Entity SQL's ORDER BY clause.
You could use SqlQuery as shown here to use a SQL string (with parameters of course) that uses the COLLATE clause :
var query = "select Name from Customers " +
" where Name COLLATE Turkish_CI_AI like #name";
var results = myContext.Customers
.SqlQuery(query,new SqlParameter("#name","%ozgur%"))
.ToList();
I'd advise caution though. LIKE '%...%' can't benefit from any indexes that cover the name field and will have to search the entire table. Even Name = #name COLLATE ... may not use any indexes the collation doesn't match the collation the index was built with.
You should consider using full text search indexes and make full text search queries for specific words, eg:
SELECT Name from Customers WHERE CONTAINS(Name ,#thatName)
Update
Another option is to use an interceptor to change the SQL generated by a clause, as shown in this SO question. That interceptor uses a regular expression to replace LIKE with CONTAINS. A simpler expression could be used to inject the COLLATE clause before LIKE
The code isn't trivial, but at least it's an option.
Why don't you use following filer clause for unicode values
Converting the collation type will cause performance issues and prevent index usage
select Name
from Customers
where Name like N'%özgür%'
You can solve this by using a normal query (via context.Database.SqlQuery) that returns an array of ids and use this ids in your linq statement.

What is the Equivalent of N'something in Persian' in C# And LINQ?

Im trying to insert something in persian into my Database (SQL server 2008) from C# code.
The problem is when u insert in sql server you just simply use N'چیزی' for utf-8.But how
Can u do that in LINQ ? (I dont wanna use stored procedures).
Thnks
Simply use the string "چیزی" and make sure your .cs files are UTF-8 too.
Use this as the parameter in a parameterized query or in whatever ORM you are using. The data access layer will take care of encoding.
LINQ to EF or LINQ to SQL will generate/use that N'' automatically everywhere:
exec sp_executesql N'update [dbo].[Users]
set [Name] = #0
where (([Id] = #1) and ([Name] = #2))
',N'#0 nvarchar(max) ,#1 int,#2 nvarchar(max) ',#0=N'User name 1',#1=1,#2=N'Vahid'
Those N'ي' (Arabic Ye) or N'ى' (Persian Ye) both are the valid UTF-8 characters. So you need to convert between them yourself (before inserting the data) and it's not the duty of EF or SQL Server.
Some examples about it (in Persian).

Is there any way to get the table hierarchy from a connection string in c#?

I have a current requirement to determine the table hierarchy from a sql statement within c#. For example, consider the following sql statement:
Select Table1.*, Table2.* from Table1
left join table2 on Table1.parentCol = Table2.childCol
That might return 7 columns, 3 for Table1 and 4 for table2. I need to know the column names, and ideally (though not mandatory) their types.
I have no control over what SQL Statement will be used, as this is a user entered field. In C# it's a very basic task to open a connection and create an SqlCommand using that statement. I have freedom to run the SQL into a SqlDataReader, or any other System.Data.SqlClient class if necessary, however I cannot find any combination that will return the columns, rather than the actual column values.
Is anyone able to help?
Many thanks and best regards
You cannot do what you are asking (easily).
More to the point, do not let users enter arbitrary TSQL (You will regret it at some point...).
Instead, create a 'Search' form that allows entering various params and use a parameterised query onto a view that joins all the tables/columns required.
There's no direct way. You'll need to parse names of all the tables from the sql query.
Once you have done that you'll need to write few queries on Information_Schema to get raw data for what you are looking for.
If you are on SQL Server, you may want to use Catalog View
ex-
Select * from sys.tables where [Name] = 'MyTable'

How do I protect this function from SQL injection?

public static bool TruncateTable(string dbAlias, string tableName)
{
string sqlStatement = string.Format("TRUNCATE TABLE {0}", tableName);
return ExecuteNonQuery(dbAlias, sqlStatement) > 0;
}
The most common recommendation to fight SQL injection is to use an SQL query parameter (several people on this thread have suggested it).
This is the wrong answer in this case. You can't use an SQL query parameter for a table name in a DDL statement.
SQL query parameters can be used only in place of a literal value in an SQL expression. This is standard in every implementation of SQL.
My recommendation for protecting against SQL injection when you have a table name is to validate the input string against a list of known table names.
You can get a list of valid table names from the INFORMATION_SCHEMA:
SELECT table_name
FROM INFORMATION_SCHEMA.Tables
WHERE table_type = 'BASE TABLE'
AND table_name = #tableName
Now you can pass your input variable to this query as an SQL parameter. If the query returns no rows, you know that the input is not valid to use as a table. If the query returns a row, it matched, so you have more assurance you can use it safely.
You could also validate the table name against a list of specific tables you define as okay for your app to truncate, as #John Buchanan suggests.
Even after validating that tableName exists as a table name in your RDBMS, I would also suggest delimiting the table name, just in case you use table names with spaces or special characters. In Microsoft SQL Server, the default identifier delimiters are square brackets:
string sqlStatement = string.Format("TRUNCATE TABLE [{0}]", tableName);
Now you're only at risk for SQL injection if tableName matches a real table, and you actually use square brackets in the names of your tables!
As far as I know, you can't use parameterized queries to perform DDL statements/ specify table names, at least not in Oracle or Sql Server. What I would do, if I had to have a crazy TruncateTable function, that had to be safe from sql injection would be to make a stored procedure that checks that the input is a table that is safe to truncate.
-- Sql Server specific!
CREATE TABLE TruncableTables (TableName varchar(50))
Insert into TruncableTables values ('MyTable')
go
CREATE PROCEDURE MyTrunc #tableName varchar(50)
AS
BEGIN
declare #IsValidTable int
declare #SqlString nvarchar(50)
select #IsValidTable = Count(*) from TruncableTables where TableName = #tableName
if #IsValidTable > 0
begin
select #SqlString = 'truncate table ' + #tableName
EXECUTE sp_executesql #SqlString
end
END
If you're allowing user-defined input to creep into this function via the tablename variable, I don't think SQL Injection is your only problem.
A better option would be to run this command via its own secure connection and give it no SELECT rights at all. All TRUNCATE needs to run is the ALTER TABLE permission. If you're on SQL 2005 upwards, you could also try using a stored procedure with EXECUTE AS inside.
CREATE OR REPLACE PROCEDURE truncate(ptbl_name IN VARCHAR2) IS
stmt VARCHAR2(100);
BEGIN
stmt := 'TRUNCATE TABLE '||DBMS_ASSERT.SIMPLE_SQL_NAME(ptbl_name);
dbms_output.put_line('<'||stmt||'>');
EXECUTE IMMEDIATE stmt;
END;
Use a stored procedure. Any decent db library (MS Enterprise Library is what I use) will handle escaping string parameters correctly.
Also, re:parameterized queries: I prefer to NOT have to redeploy my app to fix a db issue. Storing queries as literal strings in your source increases maintenance complexity.
Have a look at this link
Does this code prevent SQL injection?
Remove the unwanted from the tableName string.
I do not think you can use param query for a table name.
There are some other posts which will help with the SQL injection, so I'll upvote those, but another thing to consider is how you will be handling permissions for this. If you're granting users db+owner or db_ddladmin roles so that they can truncate tables then simply avoiding standard SQL injection attacks isn't sufficient. A hacker can send in other table names which might be valid, but which you wouldn't want truncated.
If you're giving ALTER TABLE permissions to the users on the specific tables that you will allow to be truncated then you're in a bit better shape, but it's still more than I like to allow in a normal environment.
Usually TRUNCATE TABLE isn't used in normal day-to-day application use. It's used for ETL scenarios or during database maintenance. The only situation where I might imagine it would be used in a front-facing application would be if you allowed users to load a table which is specific for that user for loading purposes, but even then I would probably use a different solution.
Of course, without knowing the specifics around why you're using it, I can't categorically say that you should redesign, but if I got a request for this as a DBA I'd be asking the developer a lot of questions.
Use parameterized queries.
In this concrete example you need protection from SQL injection only if table name comes from external source.
Why would you ever allow this to happen?
If you are allowing some external entity (end user, other system, what?)
to name a table to be dropped, why won't you just give them admin rights.
If you are creating and removing tables to provide some functionality for end user,
don't let them provide names for database objects directly.
Apart from SQL injection, you'll have problems with name clashes etc.
Instead generate real table names yourself (e.g DYNTABLE_00001, DYNTABLE_00002, ...) and keep a table that connects them to the names provided by user.
Some notes on generating dynamic SQL for DDL operations:
In most RDBMS-s you'll have to use dynamic SQL and insert table names as text.
Be extra careful.
Use quoted identifiers ([] in MS SQL Server, "" in all ANSI compliant RDBMS).
This will make avoiding errors caused by invalid names easier.
Do it in stored procedures and check if all referenced objects are valid.
Do not do anything irreversible. E.g. don't drop tables automatically.
You can flag them to be dropped and e-mail your DBA.
She'll drop them after the backup.
Avoid it if you can. If you can't, do what you can to minimize rights to other
(non-dynamic) tables that normal users will have.
You could use SQLParameter to pass in tableName value. As far as I know and tested, SQLParameter takes care of all parameter checking and thus disables possibility of injection.
If you can't use parameterized queries (and you should) ... a simple replace of all instances of ' with '' should work.
string sqlStatement = string.Format("TRUNCATE TABLE {0}", tableName.Replace("'", "''"));

Is it possible to use query parameters to fill the IN keyword

Imagine a table with GUIDs as primary key. I would like to select a few of these rows based on their primary key. I would like to use a query like:
SELECT * FROM mytable WHERE id IN ('firstguidhere','secondguidhere');
I am using ADO.NET to query the database, so I would like to use a parametrized query instead of dynamic sql, which would obviously work, but I want to retain the benefits of parametrized queries (security, escaping, etc...).
Is it possible to fill the collection for the IN-clause using sql-parameters?
You could pass the list of GUIDs as a comma-separated string parameter and use a table-valued UDF to split them into a table to use in your IN clause:
SELECT *
FROM my_table
WHERE id IN (SELECT id FROM dbo.SplitCSVToTable(#MyCSVParam))
Erland Sommarskog has an interesting article with examples of how to split comma-separated strings into tables using a UDF.
(For performance reasons, you should ensure that your UDF is inline table-valued, rather than multi-statement.)

Categories