add object values to a database - c#

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.

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.

How to pass columns as parameters in dynamic sql - C#, sql server compact

This question is an extension to another I asked Here
I have a win form which has checkbox controls in it. The names of the checkboxes matches column names of a table. I can not normalize the tables cause of huge data involved, already received for the live project. so everything stays as it is.
I get the selected checbox names as a csv col1,col2,col3 which later i concatenate it to sql string.(no SPs as its a sql compact 3.5 sdf dbase).
In my GetData() method of the DataAccess class i form the sql string. But to avoid sql injections how can ensure that the column names passed are validated.
// Get Data
// selectedMPs: string csv, generated from the list of selected posts(checkboxes) from the UI, forming the col names in select
public static DataTable GetDataPostsCars(string selectedMPs, DateTime fromDateTime, DateTime toDateTime)
{
DataTable dt;
//string[] cols = selectedMPs.Split(','); //converts to array
//object[] cols2 = cols;//gets as object array
//=== using cols or cols 2 in String.Format does not help
// this WORKS, but as i am aware its prone to injections. so how can i validate the "selectedMPs" that those are columns from a list or dictionary or so on? i am not experienced with that.
string sql = string.Format(
"SELECT " + selectedMPs + " " +
"FROM GdRateFixedPosts " +
"WHERE MonitorDateTime BETWEEN '" + fromDateTime + "' AND '" + toDateTime +
using (cmd = new SqlCeCommand(sql,conn))
{
cmd.CommandType = CommandType.Text; //cmd.Parameters.Add("#toDateTime",DbType.DateTime);
dt = ExecuteSelectCommand(cmd);
}
return dt;
}
this WORKS, but as i am aware its prone to injections. so how can i validate the "selectedMPs" that those are columns from a list or dictionary or so on? i am not experienced with that. I would really appreciate your help. Thanks in advance.
This is the only possible approach, and there is no risk of injection with SQL Server Compact, as that database engine only executes a single statement per batch.

How to bind array data to SqlCommand.Parameter?

It's possible to perform this operation without "foreach" ???
I would understand if there are library functions to associate a parameter a list of data and perform N insert all together
String SQL_DETAIL = "INSERT INTO [ImportDetail] " +
" ([idMaster] " +
" ,[operation] " +
" ,[data]) " +
" VALUES " +
" (#a,#b,#c) ";
foreach (ImportDetail imp in this.lstImportDetail )
{
SqlCommand dettCommand = new SqlCommand(SQL_DETAIL, myTrans.Connection);
dettCommand.Transaction = myTrans;
dettCommand.Parameters.Add("a", SqlDbType.Int).Value = imp.IdMaster;
dettCommand.Parameters.Add("b", SqlDbType.NVarChar).Value = imp.Operation;
dettCommand.Parameters.Add("c", SqlDbType.NVarChar).Value = imp.Data;
i =i+ (int)dettCommand.ExecuteNonQuery();
}
Thank for help
If you were feeling frisky, you could create a user-defined table type and put the data from all your ImportDetail objects into a DataTable. This wouldn't totally alleviate the need for a loop, though -- it just makes it more efficient since you're only transforming data in memory instead of passing it to a remote database. Once you have your DataTable populated to match the schema of your table type, you can pass it as a parameter to a stored procedure to handle your INSERTs. The procedure can be made transactional if you'd like, and since your input data will already be in a table (of sorts), the SQL for the stored procedure should be pretty simple, as well.
For more info on user-defined table types and how they're used in .NET, check out this link: http://msdn.microsoft.com/en-us/library/bb675163.aspx
Going a little further, if this is something you have to do quite often, it's not out of the realm of possibility to turn this into some sort of extension method on IEnumerable to keep things DRY.
Is this the sort of solution you were looking for? It's a little hard for me to tell given the wording of the question.
You can define two array list:
the first will have the name of the parameter and the second its value:
ArrayList arrayName = new ArrayList { };
ArrayList arrayValue = new ArrayList { };
arrayName.Add("#Parameter1");
arrayName.Add("#Parameter2");
arrayValue.Add(value1);
arrayValue.Add(value2);
for (int i = 0; i < arrayName.Count; i++)
{
cmd.Parameters.AddWithValue(arrayName[i].ToString(), arrayValue[i]);
}
Then execute command

How do you set Left and Center Align when using a SQL insert?

I am inserting new rows into a dataGridView Table. I have a sql sting that looks like this.
sql = #"INSERT INTO " + myNameRange + " VALUES ("+rowString+")";
My method that works looks like this.
public static void inSertRow(string myNameRange, string rowString)
{
string sql = null;
sql = #"INSERT INTO " + myNameRange + " VALUES ("+rowString+")";
if (myCommand == null)
{
MessageBox.Show("ERROR :: dfsdfsdf");
}
myCommand.CommandText = sql;
myCommand.ExecuteNonQuery();
}
When I bring in "rowString" into the VALUES portion of the sql string, my question is;
Is there a way to set the "justification" / alignment of the information in that cell? Can it be done within the sql string?
So if my rowString of information coming in is ('city', 'state', 'zip') and I want city and state to be left aligned in the cell, but zip to be centered aligned.. can this be done?
Thanks
Formatting the way data looks is not the job of a database. When you insert your data you want to keep it a simple as possible. The time to format your data is when you read the data from the database.
You may want to justify your data centrally in one application but not in another. However the value stored in the database remains the same.
If you want to remove leading or trailing spaces use the ltrim and rtrim functions.

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.

Categories