views:

71

answers:

4

I'm trying to create a class to represent the value of a column in SQL. Here's the final goal I want to reach:

public string GenerateInsertSql()
{
  StringBuilder insertSql = new StringBuilder();
  insertSql.Append("INSERT INTO " + SchemaName + "." + TableName + "\n");
  insertSql.Append("(\n");
  int counter = 0;
  foreach (ColumnValue columnValue in _insertValues)
  {
    if (counter > 0) insertSql.Append(",");
    counter++;
    insertSql.Append(columnValue.ColumnName).Append("\n");
  }
  insertSql.Append(")\n");
  insertSql.Append("VALUES\n");
  insertSql.Append("(\n");
  counter = 0;
  foreach (ColumnValue columnValue in _insertValues)
  {
    if (counter > 0) insertSql.Append(",");
    counter++;
    insertSql.Append(columnValue.SqlValue).Append("\n");
  }
  insertSql.Append(")\n");
}

So the class is the ColumnValue class mentioned above. The ColumnValue class needs a Value property which can presumably be any basic .NET type (int, string etc). The class also has a property, SqlValue, which provides a string representation of the Value property which I can use in the generated SQL statement. So if Value is an int, then SqlValue just gives Value.ToString(), whereas if Value is a string, SqlValue needs to check if the string is null in order to either return 'NULL' or the Value property itself.

Initially I tried to have Value as an object and SqlValue to test the type of Value in a switch statement:

public string SqlValue
{
  get
  {
    switch (Value.GetType())
    {
      ...
    }
  }
}

But then I get 'Value of integral type expected'. So I can't check an object's type.

Next I tried generics. I changed the ColumnValue class to ColumnValue<T>, with the Value property as follows:

public T Value { get; set; }

And then, in the SqlValue property, another check of the type of T, but I'm not allowed to do that either.

Is there a way to achieve this in C# without simply creating separate classes to handle each possible type of column?

A: 

switch keyword can take only integers (correctly speaking, integral type (see here)). But you can always use "if" statements. For example,

var t = value.GetType();
if (t == typeof(string))
{
   ..
}
else if (t == typeof(int))
{
}
else if ...

You can also use "is" keyword. For example,

if (value is string) 
{
  ...
}
else if (value is int)
{
  ...
}
else if ...

"is" operator will also check within inheritance hierarchy but I don't think that will be the case in your usage.

Lastly, I hope that whatever SqlValue implementation that you are going to do will handle escaping (for example - quotes within string values) and will protect against sql injection attacks. You may consider generating parameterized query insetad (i.e. add parameter for each column in the query and then pass actual values as parameter values - so you won't need SqlValue property at all).

VinayC
It's not true that switch only takes ints. Might be best to edit that one.
David
Regarding your final paragraph, it's the null checking for nullable types that is required here - that's the purpose of the SqlValue property.
David
@David, thanks for pointing out - corrected now.
VinayC
Sorry, I misunderstood your post. switch can indeed only accept 'integral types'. I had assumed it was the GetType() call that was failing, but it was in fact its use in a switch that was the problem. Thank you.
David
VinayC - Switch statement can only take constant values - this includes strings. It is not true (in c#) that switch can only take integral type.
Matt Ellen
A: 

If you use parameters, you can have your SqlValue just return an object.

Your example will need to add quotes around strings and deal with culture issues (formatting of double, date).

Hans Kesting
And also testing for null... you're right about the quotes and date formats.
David
A: 

u can use

string str = Value.GetType().FullName

and then use switch case.

for database its better to use EntityFramework instead of hand written DAL

SaeedAlg
Thanks for the heads up. I'm using the code to test my implementation of NHibernate as a DAL. The code inserts some values into the tables, then the DAL retrieves them as objects and I compare the properties. It's much more time-consuming than I thought!
David
A: 

You can also use Type.GetTypeCode(Value.GetType()), which will turn it into the enum TypeCode which has all the primitive values retrieval from a database, especially enumerated. With the exception of Guid which will come up as object, but you can handle that in the object block.

Michael B
Useful. Thanks.
David