Hide queries without ORM - c#

So I have an application where I need to save data to database, but the data structure is based on user. Basically user inserts a .csv or .txt file to my application and it generates table with data from the file. It is great and sweet, but I want to hide my queries and make them more manageable. Currently I have manager classes like:
TableManager
public static void CreateDocumentTable(string tableName, object[] values)
{
var query = QueryManager.CreateTable(tableName, headers);
query.Execute();
}
QueryManager
public static DMQuery CreateTable(string tableName, DMAttribute[] values)
{
var query = new DMQuery() { Command = $"CREATE TABLE IF NOT EXISTS {tableName} (" };
query.Parameters = values;
query.Command += ValuesToQuery(values);
query.Command += ")";
return query;
}
The thing is I can't use Entity Framework, because most of this is not static. Table structure changes based on csv so I never know what kind of columns I will have to take care of.
Also it is not very secure right know. I'm not looking for best security system, but just something that can hide strings like "CREATE TABLE ...."

Related

Am I in danger of SQL injection if I only allow words from a specific list?

I have some code that accesses a table in a SQL Server database:
...
if (GetViewNames(connection).Contains(name))
{
query = "SELECT * FROM [" + name + "]";
}
...
Here is "GetViewNames":
private List<string> GetViewNames(SqlConnection connection)
{
List<string> viewNames = new List<string>();
foreach (DataRow row in connection.GetSchema("Views").Rows)
{
// The third element in the "rows" array is the name of the view.
viewNames.Add(row[2].ToString());
}
return viewNames;
}
All I want to know is if this code is open to SQL injection. name is a string passed through the URL (bad, I know), but it will only ever query the DB if name is in my list of tables, right? Or am I missing something here?
I'm no security expert, so please be kind with your responses.
There is nothing stopping you from creating a view named users];DROP TABLE [users. It should be clear what happens when the code is executed with this view name.
If all of your views are named by yourself, it is possible to keep it safe, but I would recommend using QUOTENAME just in case.

Backup SQL Server Schema With Data

I've been tasked with creating a backup of the data in our "default schema" database dbo to the same database using a new schema called dbobackup.
I honestly do not understand what this means as far as a database goes. Apparently, it is like having a database backup inside the existing database. I guess there is some advantage to doing that.
Anyway, I can't seem to find anywhere online that will allow me to do this.
I have found a few posts on here about copying the schema without data, but I need the data too.
Backup SQL Schema Only?
How do I check to see if a schema exists, delete it if it does, and then create a schema that accepts data in the current database?
Once I have the new schema created, can I dump data in there with a simple command like this?
SELECT * INTO [dbobackup].Table1 FROM [dbo].Table1;
That line only backs up one table, though. If I need to do this to 245 tables for this particular customer, I'd need a script.
We have several customers, too, and their databases are not structured identically.
Could I do something along these lines?
I was thinking about creating a small console program to walk through the tables.
How would I modify something like the code below to do what I want?
public static void Backup(string sqlConnection)
{
using (var conn = new SqlConnection(sqlConnection))
{
conn.Open();
var tables = new List<String>();
var sqlSelectTables = "SELECT TableName FROM [dbo];";
using (var cmd = new SqlCommand(sqlSelectTables, conn))
{
using (var r = cmd.ExecuteReader())
{
while (r.Read())
{
var item = String.Format("{0}", r["TableName"]).Trim();
tables.Add(item);
}
}
}
var fmtSelectInto = "SELECT * INTO [dbobackup].{0} FROM [dbo].{0}; ";
using (var cmd = new SqlCommand(null, conn))
{
foreach (var item in tables)
{
cmd.CommandText = String.Format(fmtSelectInto, item);
cmd.ExecuteNonQuery();
}
}
}
}
SQL Server already has this built in. If you open SQL Server Management Studio and right click on the database you want to back up, then select all tasks then backup, you will get an option to back up your database into an existing database.
This is the important part and why you should use the built in functionality: You must copy the data from one DB to the other DB in the correct order or you'll get foreign key errors all over the place. If you have a lot of data tables with a lot of relationships, this will really be hard to nail down on your own. You could write code to make a complete graph of all of the dependencies and then figure out what order to copy the table data (which is essentially what SQL Server already does).
Additionally, there are third-party programs available to do this type of backup as well (see: Google).
This is sort of a "work in progress" approach I got started with that looks promising:
public static void CopyTable(
string databaseName, // i.e. Northwind
string tableName, // i.e. Employees
string schema1, // i.e. dbo
string schema2, // i.e. dboarchive
SqlConnection sqlConn)
{
var conn = new Microsoft.SqlServer.Management.Common.ServerConnection(sqlConn);
var server = new Microsoft.SqlServer.Management.Smo.Server(conn);
var db = new Microsoft.SqlServer.Management.Smo.Database(server, databaseName);
db.Tables.Refresh();
for (var itemId = 0; itemId < db.Tables.Count; itemId++)
{
var table = db.Tables.ItemById(itemId);
if (table.Name == tableName)
{
table.Schema = String.Format("{0}", DatabaseSchema.dboarchive);
table.Create();
}
}
}
The only issue I am currently running into is that my db variable always comes back with Tables.Count == 0.
If I get a chance to fix this, I will update.
For now, I've been told to remove this piece of code and check my code in.

Dynamically adjust Create Table and Insert Into statement based on custom class

All right, this is the bigger question linked to this link which I tried to delete but couldnt any more. People said I should never post part of the problem due to the x y problem link, which is fair enough. So here it comes.
Lets say I have a class:
public class CustomClass
{
public string Year;
public double val;
public string Tariff;
public string ReportingGroup;
}
I now have some process that creates a list of this class with results (in reality its a bigger class but that shouldnt matter).
I now create an Access table if it doesnt exist yet. For this I need the class members and ideally also the type (currently all text!):
public static void createtable(string path, string tablename, string[] columnnames)
{
try
{
string connectionstring = creadteconnectionstring(path);
OleDbConnection myConnection = new OleDbConnection(connectionstring);
myConnection.Open();
OleDbCommand myCommand = new OleDbCommand();
myCommand.Connection = myConnection;
string columnam = "[" + columnnames[0] + "] Text";
for (int i = 1; i < columnnames.Length; i++)
{
columnam = columnam + ", [" + columnnames[i] + "] Text";
}
myCommand.CommandText = "CREATE TABLE [" + tablename + "](" + columnam + ")";
myCommand.ExecuteNonQuery();
myCommand.Connection.Close();
Console.WriteLine("Access table " + tablename + " created.");
}
catch
{
Console.WriteLine("Access table " + tablename + " already exists.");
return;
}
}
Note column name contains actually the names of the class members of custom class. Then I paste the data into it:
public static void appenddatatotable(string connectionstring, string tablename, string datstr, List<CustomClass> values)
{
string commandtext = "INSERT INTO " + tablename + " ([RunDate],[ReportingGroup], [Tariff], [Year], [Quarter]) VALUES(#RunDate, #ReportingGroup, #Tariff, #Year, #Quarter)";
using (var myconn = new OleDbConnection(connectionstring))
{
myconn.Open();
using (var cmd = new OleDbCommand())
{
foreach (var item in values)
{
cmd.CommandText = commandtext;
if (string.IsNullOrEmpty(item.val))
item.val = "";
cmd.Parameters.Clear();
cmd.Parameters.AddRange(new[] { new OleDbParameter("#RunDate", datstr), new OleDbParameter("#ReportingGroup", item.RG), new OleDbParameter("#Tariff", item.tar), new OleDbParameter("#Year", item.yr), new OleDbParameter("#Quarter", item.val)});
cmd.Connection = myconn;
//cmd.Prepare();
cmd.ExecuteNonQuery();
}
}
}
}
This all works fine.
However, say I change sth in my process that also needs another calculation that yields value2, then I need to change the class, the createtable and teh appenddatatotable function. I would like to only update the class.
So, you are trying to build your own ORM (Object Relational Mapper) for C# and MS Access databases.
While this is an interesting endeavour as a learning experience, it's a problem that is hard to tackle properly.
What you need to do is use reflection in your createtable to determine the details metadata necessary (property names, property types) to construct the CREATE TABLE SQL Statement.
Then you could use something like DBUtils.CreateTable<CustomClass>(connStr); to create the table.
Since you have not mentioned reflection in this question, you really need to first learn as much as you can about it, and experiment with it first before you can answer your own question.
You previous question had some answers that already mentioned using reflection and showed you how to get the property names and types of arbitrary classes.
Once you get through that hurdle, you will encounter other problems:
How to define type lengths
Especially for strings, in .Net they can be considered almost unlimited (for most use anyway) but in Access, a string of less than 255 characters is not the same type as a larger one.
How to define your Primary key.
As a general rule, all tables in a database must have a Primary Key field that is used to identify each record in a table in a unique way.
In an ORM, it's really important, so you can easily fetch data based on that key, like GetByID<CustomClass>(123) would return an instance of your CustomClass that contains the data from record whose primary key ID is 123.
How to define indexes in your database.
Creating tables is all good and well, but you must be able to define indexes so that queries will have expected performance.
How to define relationships between tables.
Databases are all about relational data, so you need a way to define these relationships within your classes so that a class PurchaseOrder can have a list of PurchaseItem and your code understand that relationship, for instance when you need to delete a given Purchase Order, you will also need to delete all of its items in the database.
How to only load what you need.
Say you have a Customer class that has a PurchaseOrders property that is in fact a List<PurchaseOrders>. Now, if you load the data of a particular customer, to display their phone number for instance, you do not want to also pull all the possible 1,000s or orders they have made over the years, each of these having maybe 100s of items...
How to execute queries and use their results.
Once you have mapped all your tables to classes, how do you query your data?
linq is fantastic, but it's very hard to implement by yourself, so you need a good solution to allow you to make queries and allow your queries to return typed data.
For many of these issues, custom Attributes are the way to go, but as you move along and make your ORM more powerful and flexible, it will increase in complexity, and your early decisions will sometimes weigh you down and complicate things further because, let's face it, building an ORM from scratch, while an interesting experience, is hard.
So, you really have to think about all these questions and set yourself some limits on what you need/want from the system before jumping into the rabbit hole.

Create Reusable Linq To SQL For Stored Procedures

I am working on a new project that needs to use Linq To SQL. I have been asked to create a generic or reusable Linq to SQL class that can be used to execute stored procedures.
In ADO.Net I knew how to do this by just passing in a string of what I wanted to execute and I could pass in different strings for each query I need to run:
SqlCommand cmd = new SqlCommand("myStoredProc", conn); // etc, etc
I am struggling with how to create something similar in Linq To SQL, if it is even possible. I have created a .dbml file and added my stored procedure to it. As a result, I can return the results using the code below:
public List<myResultsStoreProc> GetData(string connectName)
{
MyDataContext db = new MyDataContext (GetConnectionString(connectName));
var query = db.myResultsStoreProc();
return query.ToList();
}
The code works but they want me to create one method that will return whatever stored procedure I tell it to run. I have searched online and talked to colleagues about this and have been unsuccessful in finding a way to create reusable stored proc class.
So is there a way to create a reusable Linq to SQL class to execute stored procs?
Edit:
What I am looking for is if there is a way to do something like the following?
public List<string> GetData(string connectName, string procedureName)
{
MyDataContext db = new MyDataContext (GetConnectionString(connectName));
var query = db.procedureName();
return query.ToList();
}
I have reviewed the MSDN docs on Linq To Sql and these are showing the table in the IEnumerable:
IEnumerable<Customer> results = db.ExecuteQuery<Customer>(
#"select c1.custid as CustomerID, c2.custName as ContactName
from customer1 as c1, customer2 as c2
where c1.custid = c2.custid"
);
I am looking for something very generic, where I can send in a string value of the stored proc that I want to execute. If this is not possible, is there any documentation on why it cannot be done this way? I need to prove why we cannot pass a string value of the name of the procedure to execute in Linq To Sql
DataContext.ExecuteCommand is not quite what you are looking for, as it only returns an int value. What you want instead is DataContext.ExecuteQuery, which is capable of executing a stored procedure and returning a dataset.
I would create a partial class for your DBML in which to store this function.
public List<T> GetDataNoParams(string procname)
{
var query = this.ExecuteQuery<T>("Exec " + procname);
return query.ToList();
}
public List<T> GetDataParams(string procname, Object[] parameters)
{
var query = this.ExecuteQuery<T>("Exec " + procname, parameters);
return query.ToList();
}
To call a stored procedure you would do:
GetDataNoParams("myprocedurename");
or
GetDataParams("myotherprocedure {0}, {1}, {2}", DateTime.Now, "sometextValue", 12345);
or
GetDataParams("myotherprocedure var1={0}, var2={1}, var3={2}", DateTime.Now, "sometextValue", 12345);
If you want to call procedures with no return value that is easy enough too, as I'm sure you can see, by creating a new method that doesn't store/return anything.
The inspiration came from http://msdn.microsoft.com/en-us/library/bb361109(v=vs.90).aspx.
The simplest answer to your question is that you can grab the Connection property of your MyDataContext and create and execute your own SqlCommands just like you would in straight up ADO.Net. I'm not sure if that will serve your purposes, especially if you want to retrieve entities from your LINQ to SQL model.
If you want to return entities from the model, then have a look at the DataContext.ExecuteCommand method.
When we drop a Table or StoredProcedure in our .dbml file it creates its class which communicates with the data layer and our business logic.
In Linq to SQL we have to have the StoredProcedures or Tables present in the .dbml file otherwise there is no way to call a generic method in Linq to SQL for calling a stored procedure by passing its name to a method.
But in ADO.Net we can do it (like you know)
SqlCommand cmd = new SqlCommand("myStoredProc", conn);

add object values to a database

I am storing an applicants text box data in a session class. I am calling the session class and storing it in an object.
How can i loop through the items, and add them to a database?
Can i loop through and concatenate into a string? I am using a data access layer and an oracle database.
Here is the string for the insert in the DAL. I dont have the function complete since i dont know what to pass in at this point. But, i do have a runquery function that works that i pass the string sql into.
public void AddJobApplication()
{
string sql = "insert into JOBQUESTIONS (JOBAPPLICATIONID, QUESTIONTEXT, TYPEID, HASCORRECTANSWER, CORRECTANSWER, ISREQUIRED) VALUES (" + JobID + ", \'" + QuestionText + "\', " + TypeID + ", " + HasCorrectAnswer + ", \'" + CorrectAnswer + "\', " + IsRequired + ")";
RunQuery(sql);
}
Here is my session class
public class JobApplicantSession
{
public JobApplication ApplicationSession
{
get {if (HttpContext.Current.Session["Application"] != null)
return (JobApplication)HttpContext.Current.Session["Application"];
return null; }
set{ HttpContext.Current.Session["Application"] = value; }
}
}
Then, i can retrieve that session and store it in an object
JobApplicantSession _sessions = new JobApplicantSession();
JobApplication _application;
_application = new JobApplication(jobID);
_sessions.ApplicationSession = _application; //_application holds all my saved textbox texts
JobApplication application;
var jas = new JobApplicantSession();
application = jas.ApplicationSession; //holds all my session text
I want to insert multiple records in table JOBQUESTIONS and i have all these records in the application variable
Thank you!!!
Couple of things:
First its seems that JobApplication is an object which is holding data for a particular job application. You can't do iteration on that. You probably need a list of JobApplication and your object application should be something similar to
List<JobApplication> applications = new List<JobApplication>();
You can only iterate using foreach through an object if it has Ienumerable interface implemented. (Generally speaking an Array of objects or List of Objects)
For inserting data in database, once you were able to iterate and construct a query, I would recommend building a single insert statement with multiple values. Then call it once to insert data in database. Please do take care of SQL Injection. Also if you think that using multiple insert statements suits your need then use a transaction
Firstly instead of concatenating parameters, it will be better to use parameterized queries since currently you are open to an SQL injection attack. This article could get you started on that : http://www.csharp-station.com/Tutorials/AdoDotNet/Lesson06.aspx
Pass JobApplication object tp SQL function (or if needed a collection of it in the form of List or array,) you can loop through each record and run insert queries against it. It's a performance concern in the sense that you are hitting database more than once. But if your application is small then it's not a major issue. There are ways to send the insert for more than one record in one go using something like Dataset but that might be a little advance for you currently, so if you don't have to look into it then I would suggest to just loop through your JobApplicationCollection.

Categories