checking database rights on certain user - c#

I am given connection to a database which is owned by another company. The user that they gave to me has restricted privilidges, meaining that I can only make select queries on certain views.
I got a little problem here since the other company is not being so cooperative. They change my users password without telling me, or they change the names of the views. Since there are more than 40 views I want to make an automatic system that checks if everything is alright.
My question is what kind of checks I can make on the views and database? is just trying the connection to open and making select * queries for each view enough?
BTW the database is SQLServer 2008 R2 and I use C#.

Here is a function for checking that all required views exists:
bool IsAllviewsExists()
{
string DatabaseName= "Your_DB_NAME";
string[] viewsInDB = GetAllViewsNamesInDB();
for (int i = 0; i < viewsInDB.Length; ++i)
{
using (SqlCommand cmd = CreateSqlCommand(String.Format("SELECT id FROM sysobjects WHERE ID = OBJECT_ID('{0}.dbo.{1}') AND (type = 'V')", DatabaseName,viewsInDB [i])))
{
using (DataTable objects = ExecuteDataTableQuery(cmd))
{
if (objects.Rows.Count == 0)
{
return false;
}
}
}
}
return true;
}
The functions that are called from IsAllviewsExists :
(Pleas note that they assume you have a data member of a connection called _conn)
SqlCommand CreateSqlCommand(string sql, SqlParameterCollection parameters)
{
SqlCommand cmd = _conn.CreateCommand();
cmd.Connection = _conn;
cmd.CommandText = sql;
if (parameters != null)
foreach (SqlParameter param in parameters)
cmd.Parameters.Add(param);
return cmd;
}
DataTable ExecuteDataTableQuery(SqlCommand cmd)
{
DataTable table = null;
using (SqlDataAdapter adapter = new SqlDataAdapter(cmd))
{
table = new DataTable();
try
{
adapter.Fill(table);
}
catch (SqlException sqlEx)
{
rethrow;
}
}
return table;
}

Related

Get Data from stored procedure as Datatable

I have a method to retrieve data from a database using a stored procedure as a DataTable like:
public DataTable GetTableBySQL(string sql)
{
SqlCommand cmd = new SqlCommand(sql.ToString(), this.dbconn)
{
CommandTimeout = 0,
CommandType = CommandType.Text
};
DataTable tbl = new DataTable("Table1")
{
Locale = System.Globalization.CultureInfo.InvariantCulture
};
SqlDataAdapter da = new SqlDataAdapter(cmd);
try
{
da.SelectCommand.CommandTimeout = 0;
da.Fill(tbl);
}
catch (SqlException e)
{
this.HandleSQLError(e, "GetTableBySQL", sql.ToString());
}
finally
{
cmd.Dispose();
da.Dispose();
}
return tbl;
}
Now I call the stored procedure like this:
var empList = db.GetTableBySQL("$exec getMySP");
But when I execute, it just don't return any columns.
What am I doing wrong? Regards
There are three main problems here (other smaller ones, but three that are important):
The $exec part of the SQL doesn't mean anything. Maybe you just want exec.
When the bad SQL fails, the error is hidden from the program, so you don't really know what happened.
The method signature doesn't support query parameters, and therefore will force you to write horribly insecure code that will result in someone hacking your application. Probably sooner rather than later. This is really bad, and you should not ignore it.
Try something more like this:
public DataTable GetTableBySQL(string sql, params SqlParameter[] parameters)
{
var result = new DataTable();
//ADO.Net really does work better when you create a **NEW** connection
// object for most queries. Just share the connection string.
//Also: "using" blocks are a better way to make sure the connection is closed.
using (var dbconn = new SqlConnection(this.dbConnectionString))
using (var cmd = new SqlCommand(sql, dbconn))
using (var da = new SqlDataAdapter(cmd))
{
cmd.CommandTimeout = 0;
// A number of the properties set on the cmd and tbl variables just set the same value that was already there, didn't accomplish anything
//It's hard to understate how important it is to use parameterized queries.
if (parameters != null && parameters.Length > 0)
{
cmd.Parameters.AddRange(parameters);
}
try
{
da.Fill(result);
}
catch (SqlException e)
{
this.HandleSQLError(e, "GetTableBySQL", sql.ToString());
//you may want to re-throw here,
// or even just remove the try/catch and let the error bubble up to calling code
}
}
return result;
}
Here it is again without all the extra explanatory comments, so you can see that doing it right is less code, rather than more:
public DataTable GetTableBySQL(string sql, params SqlParameter[] parameters)
{
var result = new DataTable();
using (var dbconn = new SqlConnection(this.dbConnectionString))
using (var cmd = new SqlCommand(sql, dbconn))
using (var da = new SqlDataAdapter(cmd))
{
cmd.CommandTimeout = 0;
if (parameters != null && parameters.Length > 0)
{
cmd.Parameters.AddRange(parameters);
}
da.Fill(result);
}
return result;
}
Then call it like this:
var empList = db.GetTableBySQL("exec getMySP");

How to loop through list of complex type objects and pass to a method calling SQL Stored procedure

How to loop through a list of objects in order to pass said object to a method inserting rows in SQL db via stored procedure?
With help in this question I got to this point:
namespace NA.Controllers
{
public class NC : ApiController
{
[Route("AddNote")]
[HttpPost]
public HttpResponseMessage PostNote(List<Note> items)
{
//NoteJson deserializednote = JsonConvert.DeserializeObject<NoteJson>(item);
//Note notesdata = new Note(item);
NotesAccept.Models.INoteRepository Repository = new NotesAccept.Models.NoteDataRepository();
foreach (Note item in items)
{
item = Repository.Add(item);
}
var response = Request.CreateResponse<List<Note>>(HttpStatusCode.OK, items);
return response;
}
}
}
but now I'm stuck as item= is now an iteration variable, but I need to pass it to an method:
namespace NA.Models
{
class NoteDataRepository : INoteRepository
{
public void Add(Note item)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
else
{
String strConnString = ConfigurationManager.ConnectionStrings["conString"].ConnectionString;
SqlConnection con = new SqlConnection(strConnString);
SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "BL_IntegrationInsertNote";
cmd.Parameters.Add("#Client", SqlDbType.VarChar).Value = item.Client.Trim();
cmd.Parameters.Add("#Case", SqlDbType.VarChar).Value = item.Case;
cmd.Parameters.Add("#Text", SqlDbType.VarChar).Value = item.Text.Trim();
cmd.Parameters.Add("#When", SqlDbType.DateTime).Value = item.Date;
cmd.Parameters.Add("#Ext", SqlDbType.Bit).Value = item.Type;
cmd.Parameters.Add("#return", SqlDbType.Int).Direction = ParameterDirection.Output;
cmd.Connection = con;
try
{
con.Open();
cmd.ExecuteNonQuery();
string id = cmd.Parameters["#return"].Value.ToString();
string lblMessage = null;
lblMessage = "Record inserted successfully. ID = " + id;
}
catch (Exception ex)
{
throw ex;
}
finally
{
con.Close();
con.Dispose();
}
}
//return item;
}
IEnumerable<Note> INoteRepository.GetAll()
{
throw new NotImplementedException("getitems");
}
}
}
I'm still green-as-a-grass-newbie to C# so I've no idea how to accomplish that, especially since whole solution is still "copy&Paste" from all over the web, and whole web curiously concentrates on looping through simple types. How to do that with complex type?
As noted in other question, this is a matter of professional life and death (I'm a db dev, not a VS guru, especially not after two days and two nights).
You are still forgetting to assign that ID from DB to the item.
You also still have
return item;
in a method that does not return anything (public void Add(Note item)).
So just delete that return line.
And replace
item = Repository.Add(item);
with just
Repository.Add(item);
You can pass it as xml and iterate in sql stored procedure and do bulk insert, or you can use table datatype if sql and .net version you are using supports it.
Try this in the foreach loop:
var tempItem = item;
tempItem = Repository.Add(tempItem);

Show number of rows from a grid view

I am trying to show number of rows from a grid view using a label. I used SQL Count statement but it doesn't work. The problem is I only get only number 1 shown in the label which is not matched with the number of rows I have in my table! I have posted similar question but unfortunately no body gave a clear answer!
My codes as:
Basket.ac
public int td()
{
int customers;
//I tried this select query but still gets number 1
//String sql = String.Format("SELECT COUNT(*) FROM dbo.Baskets");
string sql = string.Format("SELECT COUNT(*) FROM Baskets");
customers = Db.RunQuery(sql).Rows.Count;
//customers = Convert.ToInt32(Db.RunQuery(sql).Rows.Count);
return customers;
}
DataBaseConn.ac
public class DataBaseConn
{
SqlConnection conn;
SqlCommand cmd;
DataTable tbl;
private void Intialise(CommandType commandtype, string DataBase)
{
conn = new SqlConnection();
cmd = new SqlCommand();
//Requirements
conn.ConnectionString = ConfigurationManager.ConnectionStrings[1].ToString();
cmd.Connection = conn;
cmd.CommandType = commandtype;
cmd.CommandText = DataBase;
conn.Open();
}
public int RunProcedure(string Procedure, SortedList ParameterV)
{
Intialise(CommandType.StoredProcedure, Procedure);
for (int i = 0; i < ParameterV.Count; i++)
try
{
if (ParameterV.GetByIndex(i) != null)
cmd.Parameters.AddWithValue(ParameterV.GetKey(i).ToString(),
PrameterV.GetByIndex(i).ToString());
}
catch { ;}
return RunUpdate();
}
public int RunUpdate(string InsDelUpd)
{
Intialise(CommandType.Text, InsDelUpd);
return RunUpdate();
}
private int RunUpdate()
{
try
{
int x = cmd.ExecuteNonQuery();
conn.Close();
return x;
}
catch (SqlException ex)
{
conn.Close();
return ex.Number;
}
}
public DataTable RunQuery(string Select)
{
Intialise(CommandType.Text, Select);
tbl = new DataTable();
tbl.Load(cmd.ExecuteReader());
conn.Close();
return tbl;
}
public bool EData(string selection)
{
if (RunQuery(selection).Rows.Count > 0)
return true;
else
return false;
}
}
Basket.aspx
lblQueue.Text = _b.td().ToString();
You don't want to return the data table's .Rows.Count - this will always be 1 (as in 1 row(s) affected) for your count(*) query.
You should instead look at using ExecuteScalar to return the first column of the first row from your query
I'm not sure how you want to build this into your DataBaseConn data helper class, but the gist of it is you need the following sequence:
using (var conn = new SqlConnection(connectionStringHere))
using (var cmd = new SqlCommand(conn))
{
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT COUNT(*) FROM Baskets";
return (int)cmd.ExecuteScalar();
}
Edit
If you aren't able to extend your DataBaseConn helper with an ExecuteScalar, then I guess you'll be able to use the existing RunQuery method which returns a DataTable. Just scrape the first column of the first row like so:
return Db.RunQuery(sql).Rows[0].Field<int>(0);
As a side note, you might look at replacing your DataHelper entirely with the Microsoft Patterns and Practices Data Application Access Block (DAAB), or, if you prefer, look at using an ORM like Entity Framework. By upgrading to a mainstream Data Access encapsulation, you won't need to spend as much time debugging data access issues like this one :)

Parameterize WHERE Clause in Query

Environment:
C#
Visual Studio 2012
.NET Framework 3.5
Hi
Could I parameterize where clause in SQL Server?
In my scenario, once a WHERE clause String is input, application will concatenate it to other part of query and execute in SQL Server then return the result.
For example,
User inputs "[CookingTime] < 30 and [Cost] < 20"
Application creates query "select [RecipeID] from [Recipes] where [CookingTime] < 30 and [Cost] < 20" and executes in SQL Server.
Application returns result to user.
For security reason, I would like to make whole WHERE CLAUSE as parameter.
But I have no idea how to achieve.
Thanks in advance.
This is how it can be done
string commandText = "UPDATE Sales.Store SET Demographics = #demographics "
+ "WHERE CustomerID = #ID;";
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(commandText, connection);
command.Parameters.Add("#ID", SqlDbType.Int);
command.Parameters["#ID"].Value = customerID;
// Use AddWithValue to assign Demographics.
// SQL Server will implicitly convert strings into XML.
command.Parameters.AddWithValue("#demographics", demoXml);
try
{
connection.Open();
Int32 rowsAffected = command.ExecuteNonQuery();
Console.WriteLine("RowsAffected: {0}", rowsAffected);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
The whole WHERE clause as parameter will be a victim of sql injection in any way. To prevent this you'd better to:
Setup proper permissions. So even in case of sql injected user can't access anything not granted. In this case sample of #Dhaval is better, because dymanic sql generation incapsulated in stored procedure requires less permissions to execute.
Check the statement for sql injection. The simplest way is to check for semicolons in order to avoid another statements in the batch. More complex and more precise way is to use t-sql DOM parser. For example:
using Microsoft.SqlServer.TransactSql.ScriptDom;
TSql110Parser parser = new TSql110Parser(true);
IList<ParseError> errors = null;
var condition = "a > 100; delete from [Recipes]";
var script = parser.Parse(new StringReader("select [RecipeID] from [Recipes] where " + condition), out errors) as TSqlScript;
if (errors.Count > 0)
{
throw new Exception(errors[0].Message);
}
foreach (var batch in script.Batches)
{
if (batch.Statements.Count == 1)
{
var select = batch.Statements[0] as SelectStatement;
if (select != null)
{
QuerySpecification query = select.QueryExpression as QuerySpecification;
if (query.WhereClause is BooleanBinaryExpression)
{
...
}
}
else
{
throw new Exception("Select statement only allowed");
}
}
else
{
throw new Exception("More than one statement detected");
}
}
You can create a dynamic query in sql server and pass the parameter from C#
Something like this
Create Procedure usp_Test
#WhereCond Varchar(max)
AS
Bgein
Set NoCount ON
Declare #SQLQuery AS Varchar(max)
Set #SQLQuery = 'Select * From tblEmployees where ' + #WhereCond
Execute sp_Executesql #SQLQuery
End
C# Code to execute the procedure
DataSet ds = new DataSet();
using(SqlConnection conn = new SqlConnection("ConnectionString"))
{
SqlCommand sqlComm = new SqlCommand("usp_Test", conn);
sqlComm.Parameters.AddWithValue("#WhereCond", WhereCond);
sqlComm.CommandType = CommandType.StoredProcedure;
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = sqlComm;
da.Fill(ds);
}
I guess the original question wanted to find out how to make it dynamically from user's input and then use proper sql parameter to do the query.
For the usage of sql parameter, normally what I do is to use a generic helper method, a quick example (not tested):
public static class SqlHelpers
{
public static IEnumerable<T> ExecuteAdhocQuery<T>(SqlConnection con, string sql, CommandType cmdType, Func<SqlDataReader, T> converter, params SqlParameter[] args)
{
try
{
using (SqlCommand cmd = new SqlCommand(sql, con) { CommandType = cmdType })
{
cmd.Parameters.AddRange(args);
if (con.State != ConnectionState.Open) { con.Open(); }
var ret = new List<T>();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
ret.Add(converter.Invoke(rdr));
}
}
return ret;
}
}
catch (Exception e)
{
// log error?
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
throw e; // handle exception...
}
}
public void Test()
{
using (SqlConnection con = new SqlConnection("connection string here"))
{
var data = ExecuteAdhocQuery(con,
"SELECT ID, Name FROM tblMyTable WHERE ID = #Id and Status = #Status;",
CommandType.Text, (x) => new { Id = x.GetInt32(0), Name = x.GetString(1) },
new SqlParameter("#Id", SqlDbType.Int) { Value = 1 },
new SqlParameter("#Status", SqlDbType.Bit) { Value = true });
Console.WriteLine(data.Count());
}
}
}
of course, this is only Reading, for Insert/Update, similar methods could be created too.
But the complicated part is how to make it dynamic with unknown number of conditions and the relationship between them. So a quick suggestion is use a delegated method or class to do the work. sample (not tested):
public static Dictionary<string, SqlParameter> GetParamsFromInputString(string inputString)
{
var output = new Dictionary<string, SqlParameter>();
// use Regex to translate the input string (something like "[CookingTime] < 30 and [Cost] < 20" ) into a key value pair
// and then build sql parameter and return out
// The key will be the database field while the corresponding value is the sql param with value
return output;
}
public void TestWithInput(string condition)
{
var parameters = GetParamsFromInputString(condition);
// first build up the sql query:
var sql = "SELECT Id, Name from tblMyTable WHERE " + parameters.Select(m => string.Format("{0}={1}", m.Key, m.Value.ParameterName)).Aggregate((m,n) => m + " AND " + n);
using (SqlConnection con = new SqlConnection("connection string here"))
{
var data = ExecuteAdhocQuery(con,
sql,
CommandType.Text,
(x) => new { Id = x.GetInt32(0), Name = x.GetString(1) },
parameters.Select(m => m.Value).ToArray());
}
}
for the static function GetParamsFromInputString, it's just a sample. actually it could be very complicated depending on your needs.
for example, you might want to include the operator (whether it's >, < or <>,...).
and you might also want to include the conjunctions between the conditions, whether it's AND or OR.
Build delegated classes to do the job if it's very complicated.

SQLite, Copy DataSet / DataTable to DataBase file

I have filled a DataSet with a Table that was created from another database file. The table is NOT in the database file which I want to be able to copy the Table to.
Now I want to save all those records (DataTable) to a newly created SQLite database file...
How can i do that?
Also I really want to avoid loops if this is possible.
The best answer is by me :) so i'll share it.This is loop but writes 100k entries in 2-3secs.
using (DbTransaction dbTrans = kaupykliuduomConn.BeginTransaction())
{
downloadas.Visible = true; //my progressbar
downloadas.Maximum = dataSet1.Tables["duomenys"].Rows.Count;
using (DbCommand cmd = kaupykliuduomConn.CreateCommand())
{
cmd.CommandText = "INSERT INTO duomenys(Barkodas, Preke, kiekis) VALUES(?,?,?)";
DbParameter Field1 = cmd.CreateParameter();
DbParameter Field2 = cmd.CreateParameter();
DbParameter Field3 = cmd.CreateParameter();
cmd.Parameters.Add(Field1);
cmd.Parameters.Add(Field2);
cmd.Parameters.Add(Field3);
while (n != dataSet1.Tables["duomenys"].Rows.Count)
{
Field1.Value = dataSet1.Tables["duomenys"].Rows[n]["Barkodas"].ToString();
Field2.Value = dataSet1.Tables["duomenys"].Rows[n]["Preke"].ToString();
Field3.Value = dataSet1.Tables["duomenys"].Rows[n]["kiekis"].ToString();
downloadas.Value = n;
n++;
cmd.ExecuteNonQuery();
}
}
dbTrans.Commit();
}
In this case dataSet1.Tables["duomenys"] is already filled with all the data i need to transfer to another database. I used loop to fill dataset too.
When you load the DataTable from the source database, set the AcceptChangesDuringFill property of the data adapter to false, so that loaded records are kept in the Added state (assuming that the source database is SQL Server)
var sqlAdapter = new SqlDataAdapter("SELECT * FROM the_table", sqlConnection);
DataTable table = new DataTable();
sqlAdapter.AcceptChangesDuringFill = false;
sqlAdapter.Fill(table);
Create the table in the SQLite database, by executing the CREATE TABLE statement directly with SQLiteCommand.ExecuteNonQuery
Create a new DataAdapter for the SQLite database connection, and use it to Update the db:
var sqliteAdapter = new SQLiteDataAdapter("SELECT * FROM the_table", sqliteConnection);
var cmdBuilder = new SQLiteCommandBuilder(sqliteAdapter);
sqliteAdapter.Update(table);
If the source and target tables have the same column names and compatible types, it should work fine...
The way to import SQL data to SQLite will take long time. When you want to import data in millions, It will take lot of time. So the shortest and easiest way to do that is just fill fetch the data from SQL database in a DataTable and insert all its rows to SQLite database.
public bool ImportDataToSQLiteDatabase(string Proc, string SQLiteDatabase, params object[] obj)
{
DataTable result = null;
SqlConnection conn = null;
SqlCommand cmd = null;
try
{
result = new DataTable();
using (conn = new SqlConnection(ConStr))
{
using (cmd = CreateCommand(Proc, CommandType.StoredProcedure, obj))
{
cmd.Connection = conn;
conn.Open();
result.Load(cmd.ExecuteReader());
}
}
using (SQLiteConnection con = new SQLiteConnection(string.Format("Data Source={0};Version=3;New=False;Compress=True;Max Pool Size=100;", SQLiteDatabase)))
{
con.Open();
using (SQLiteTransaction transaction = con.BeginTransaction())
{
foreach (DataRow row in result.Rows)
{
using (SQLiteCommand sqlitecommand = new SQLiteCommand("insert into table(fh,ch,mt,pn) values ('" + Convert.ToString(row[0]) + "','" + Convert.ToString(row[1]) + "','"
+ Convert.ToString(row[2]) + "','" + Convert.ToString(row[3]) + "')", con))
{
sqlitecommand.ExecuteNonQuery();
}
}
transaction.Commit();
new General().WriteApplicationLog("Data successfully imported.");
return true;
}
}
}
catch (Exception ex)
{
result = null;
return false;
}
finally
{
if (conn.State == ConnectionState.Open)
conn.Close();
}
}
It will take a very few time as compare to upper given answers.

Categories

Resources