I have a SQL-server and a column called CitizenshipDate. That column is of type datetime in the SQL.
However, the problem is that it can have the value '0' which is NOT a datetime value but rather a string value.
So what I'm trying to do is to handle it as a string in C# when inserting it values but get the error:
Conversion failed when converting datetime from character string.
I get that error because I'm trying to insert string into a datetime in the SQL-server.
Here is my code:
class Person {
public string PersonalIdentityNumber { get; set; }
public string SpecialIdentityNumber { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string CitizenshipDate { get; set; }
}
List<FolkbokforingspostTYPE> deserializedList = new List<FolkbokforingspostTYPE>();
deserializedList = Deserialize<List<FolkbokforingspostTYPE>>();
var myPersons = Deserialize<List<FolkbokforingspostTYPE>>()
.Select(x => new Person
{
PersonalIdentityNumber = x.Personpost.PersonId.PersonNr,
SpecialIdentityNumber = x.Personpost.PersonId.Tilltalsnamnsmarkering != null ? x.Personpost.PersonId.Tilltalsnamnsmarkering : null,
LastName = x.Personpost.Namn.Efternamn,
FirstName = x.Personpost.Namn.Fornamn,
CitizenshipDate = x.Personpost.Medborgarskap != null ? x.Personpost.Medborgarskap.Medborgarskapsdatum : null
});
string connetionString = null;
SqlDataAdapter adpter = new SqlDataAdapter();
DataSet ds = new DataSet();
XmlReader xmlFile;
connetionString = "Data Source=tsrv2062;Initial Catalog=Bums;User ID=BumsUser;Password=2tusen7Bums";
xmlFile = XmlReader.Create("navetout.xml", new XmlReaderSettings());
ds.ReadXml(xmlFile);
using (var connection = new SqlConnection(connetionString))
{
connection.Open();
DateTime datum = DateTime.Now;
string LastChangedBy = "System";
foreach (Person p in myPersons)
{
SqlCommand command1 = Avreg(p.UnregistrationReason, p.GivenNameNumber,p.ProtectedIdentity, p.CitizenshipDate, connection);
command1.Parameters.AddWithValue("#PersonalIdentityNumber", string.Format("{0}{1}", p.PersonalIdentityNumber, p.SpecialIdentityNumber));
command1.Parameters.AddWithValue("#FirstName", p.FirstName);
command1.Parameters.AddWithValue("#LastName", p.LastName);
command1.ExecuteNonQuery();
Console.WriteLine(string.Format("{0}{1}", p.PersonalIdentityNumber, p.SpecialIdentityNumber));
}
}
Console.WriteLine("Done");
// }// Put a break-point here, then mouse-over PersonalIdentityNumber... deserializedList contains everything if you need it
//catch (Exception)
// {
// throw;
// }
Console.ReadKey();
}
public static SqlCommand Avreg(string s, string t, string p, string c, SqlConnection connection)
{
var query = "UPDATE Seamen SET FirstName = #FirstName, "+
"LastName = #LastName, "+
SqlCommand command1;
//Here is the `CitizenshipDate`
if (c == "0")
{
query += ", CitizenshipDate = '0'";
command1 = new SqlCommand(query, connection);
command1.Parameters.Clear();
}
else
{
query += ", CitizenshipDate = #CitizenshipDate";
command1 = new SqlCommand(query, connection);
command1.Parameters.Clear();
command1.Parameters.AddWithValue("#CitizenshipDate", c ?? DBNull.Value.ToString());
}
//Ignore these if statements
if ((!string.IsNullOrEmpty(s)) && !string.IsNullOrEmpty(t))
{
}
else
{
query += ", GivenNameNumber = #GivenNameNumber WHERE PersonalIdentityNumber = #PersonalIdentityNumber";
t = "00";
command1 = new SqlCommand(query, connection);
command1.Parameters.Clear();
command1.Parameters.AddWithValue("#GivenNameNumber", t ?? DBNull.Value.ToString());
return command1;
}
return command1;
}
Please note that I cannot change the type in the database. I somehow need a way to insert the value from String.
Can someone help ?
If the column does not allow nulls, then you can use NULL to represent "0", and then in code, when loading the record, replace NULL with "0" in the UI. Or, if you do allow NULLS and need another value to represent "0", you can use an arbitrary date you wouldn't normally use like '1/1/1753' (the lowest value for SQL datetime) or '1/1/1900' (lowest for smalldatetime) or something like that. Any date that is these dates represents "0". So the conversion to "0" happens within the app, not stored in the database.
If your column supports null you can fix it like this:
if (c == "0")
{
query += ", CitizenshipDate = NULL--instead of '0'";
If it does not support NULL values you will have to insert a default value such as DateTime.MinValue.
Related
An error is thrown when there is no data in data base while converting a string value into int.
try {
SqlCommand cmdc = new SqlCommand("SELECT SUM(Credited_amount) FROM IMS_Credit_Dir WHERE Credit_comp_id=1 AND Crdt_typ_id=1", con);
string companya_credit_amount = null, comapnyb_credit_amount = null;
con.Open();
SqlDataReader drc = cmdc.ExecuteReader();
if (drc.HasRows)
{
while (drc.Read())
{
companya_credit_amount = drc[0].ToString();
}
drc.Close();
con.Close();
}
SqlCommand cmdcp = new SqlCommand("SELECT SUM(Credited_amount) FROM IMS_Credit_Dir WHERE Credit_comp_id=2 AND Crdt_typ_id=1", con);
con.Open();
SqlDataReader drcp = cmdcp.ExecuteReader();
if (drcp.HasRows)
{
while (drcp.Read())
{
companyb_credit_amount = drcp[0].ToString();
}
drcp.Close();
con.Close();
}
if (!Page.IsPostBack)
{
int companyA = 0,companyB=0;
if (companya_credit_amount != "") { companyA = Convert.ToInt32(credit_amount.ToString()); }
if (companyb_credit_amount != ""){ companyB = Convert.ToInt32(companyb_credit_amount); }
int total = (companyA+companyB);
count_total_lbl.Text = "Rs." + " " + total.ToString();
count_comapnya_lbl.Text = "Rs." + " " + companya_credit_amount.ToString();
count_companyb_lbl.Text ="Rs."+" "+ companyb_credit_amount.ToString();
}
}
catch(Exception ex) { Label2.Text = ex.ToString(); }
If there is value its working fine.but when there is no value in data base there is an error msg.
System.FormatException: Input string was not in a correct format.
Use IsDBNull to check for null values
Create and destroy all your type instances that implement IDisposable in using blocks. This ensures that connections are always released and resources are cleaned up.
Do not use connections across a class. Create them when needed and then dispose of them. Sql Server will handle connection pooling.
Get the native types directly, not the string equivalent! See changes to GetInt32 instead of ToString on the data reader.
You should refactor this to use SqlParameter's and make the retrieval statement generic OR get both SUM values in 1 sql call.
There is an if (!Page.IsPostBack) statement, if none of this code does anything if it is a postback then check at the top of the page and do not execute the sql statements if it is a postback. Otherwise the code is making (possibly) expensive sql calls for no reason.
try
{
int companyA = 0,companyB=0;
using(var con = new SqlConnection("connectionStringHere"))
{
con.Open();
using(SqlCommand cmdc = new SqlCommand("SELECT SUM(Credited_amount) FROM IMS_Credit_Dir WHERE Credit_comp_id=1 AND Crdt_typ_id=1", con))
using(SqlDataReader drc = cmdc.ExecuteReader())
{
if (drc.Read() && !drc.IsDBNull(0))
companyA = drc.GetInt32(0);
}
using(SqlCommand cmdcp = new SqlCommand("SELECT SUM(Credited_amount) FROM IMS_Credit_Dir WHERE Credit_comp_id=2 AND Crdt_typ_id=1", con))
using(SqlDataReader drcp = cmdcp.ExecuteReader())
{
if (drcp.Read() && !drcp.IsDBNull(0))
companyB = drcp.GetIn32(0);
}
}
// if you are not going to do anything with these values if its not a post back move the check to the top of the method
// and then do not execute anything if it is a postback
// ie: // if (Page.IsPostBack) return;
if (!Page.IsPostBack)
{
int total = (companyA+companyB);
count_total_lbl.Text = "Rs." + " " + total.ToString();
count_comapnya_lbl.Text = "Rs." + " " + companyA.ToString();
count_companyb_lbl.Text ="Rs."+" "+ companyB.ToString();
}
}
catch(Exception ex) { Label2.Text = ex.ToString(); }
Try to replace this
SELECT SUM(Credited_amount)
WITH
SELECT ISNULL(SUM(Credited_amount),0)
Also find one confusing code while converting Credited amount values
if (companya_credit_amount != "") { companyA = Convert.ToInt32(credit_amount.ToString()); }
---------^^^^^
if (companyb_credit_amount != ""){ companyB = Convert.ToInt32(companyb_credit_amount); }
I don't know about your business requirement but What i think Instead of using credit_amount value companya_credit_amount should be use to show value for companyA variable right?
You should do 2 things:
string companya_credit_amount = "", comapnyb_credit_amount = "";
Before assigning the value to these string variable you should check for db null as following:
while (drc.Read())
{
companya_credit_amount = (drc[0] != DbNull.Value) ? drc[0].ToString() : "" ;
}
Similarely
while (drcp.Read())
{
companyb_credit_amount = (drcp[0] != DbNull.Value) ? drcp[0].ToString() : "";
}
Try it.
You need to initialize credit_amount to empty and check if db value is null as shown below:
try {
companya_credit_amount = string.Empty;
companyb_credit_amount = string.Empty;
SqlCommand cmdc = new SqlCommand("SELECT SUM(Credited_amount) FROM IMS_Credit_Dir WHERE Credit_comp_id=1 AND Crdt_typ_id=1", con);
string companya_credit_amount = null, comapnyb_credit_amount = null;
con.Open();
SqlDataReader drc = cmd
c.ExecuteReader();
if (drc.HasRows)
{
while (drc.Read())
{
companya_credit_amount = drcp.IsDBNull(0)?string.Empty:Convert.ToString(drcp[0]);
}
drc.Close();
con.Close();
}
SqlCommand cmdcp = new SqlCommand("SELECT SUM(Credited_amount) FROM IMS_Credit_Dir WHERE Credit_comp_id=2 AND Crdt_typ_id=1", con);
con.Open();
SqlDataReader drcp = cmdcp.ExecuteReader();
if (drcp.HasRows)
{
while (drcp.Read())
{
companyb_credit_amount = drcp.IsDBNull(0)?string.Empty:Convert.ToString(drcp[0]);
}
drcp.Close();
con.Close();
}
if (!Page.IsPostBack)
{
int companyA = 0,companyB=0;
if (companya_credit_amount != "") { companyA = Convert.ToInt32(credit_amount.ToString()); }
if (companyb_credit_amount != ""){ companyB = Convert.ToInt32(companyb_credit_amount); }
int total = (companyA+companyB);
count_total_lbl.Text = "Rs." + " " + total.ToString();
count_comapnya_lbl.Text = "Rs." + " " + companya_credit_amount.ToString();
count_companyb_lbl.Text ="Rs."+" "+ companyb_credit_amount.ToString();
}
}
catch(Exception ex) { Label2.Text = ex.ToString(); }
I'm working with sql databases via ado.net in c# and I'm trying to pass the following update command:
cmd.CommandText = #"UPDATE VehicleContract SET regNr='#reg', assoc_id='#assort', percentage='#perc', vehicleType='#type', trailerNr='#trailer' WHERE contractId='#id'";
cmd.Parameters.AddWithValue("#id", id);
id is in int. I read it as an int. I even do a int.Parse(txtbox.text) and everything is fine. But then when I insert all the values in the boxes, press submit. I get the conversion error saying that it can't convert '#id' varchar to int... it makes no sense
Is there any specific thing I'm not doing right? Need any more details?
The whole code:
if (tbid.Text == "" || tbper.Text == "" || tbas.Text == "" || tbvt.Text == "")
{
MessageBox.Show("All fields must be filled ");
return;
}
if (tbreg.Text == "" && tbtn.Text == "")
{
MessageBox.Show("Fill at least one from: Registration nr or trailer nr");
return;
}
int id = 0;
string reg = "";
int assort = 0;
int perc = 0;
string type = "";
int trailer = 0;
try
{
id = int.Parse(tbid.Text);
Console.Write(id);
if (tbreg.Text != "")
{
reg = tbreg.Text;
}
assort = int.Parse(tbas.Text);
perc = int.Parse(tbper.Text);
type = tbvt.Text;
if (tbtn.Text != "")
{
trailer = int.Parse(tbtn.Text);
}
}
catch (Exception ee)
{
MessageBox.Show("id, assoc, perc and trailer nr must be integers ");
return;
}
SqlConnection con = new SqlConnection();
SqlCommand cmd = new SqlCommand();
con.ConnectionString = "Data Source=.;initial Catalog=Lab5;integrated security=true";
con.Open();
cmd.CommandType = CommandType.Text;
cmd.CommandText = #"UPDATE VehicleContract SET regNr='#reg', assoc_id='#assort', percentage='#perc', vehicleType='#type', trailerNr='#trailer' WHERE contractId='#id'";
cmd.Parameters.AddWithValue("#id", id);
if (reg == "")
{
cmd.Parameters.AddWithValue("#reg", DBNull.Value);
}
else
{
cmd.Parameters.AddWithValue("#reg", reg);
}
cmd.Parameters.AddWithValue("#assort", assort);
cmd.Parameters.AddWithValue("#perc", perc);
cmd.Parameters.AddWithValue("#type", type);
if (trailer == 0)
{
cmd.Parameters.AddWithValue("#trailer", DBNull.Value);
}
else
{
cmd.Parameters.AddWithValue("#trailer", trailer);
}
cmd.Connection = con;
SqlDataReader sdr = cmd.ExecuteReader();
DataTable dt = new DataTable();
dt.Load(sdr);
childgrid.DataSource = dt;
sdr.Close();
con.Close();
When you use WHERE contractId='#id' in a query you are comparing the int contractId column with the string '#id' value.
You need to use WHERE contractId=#id.
So remove single quotes around #id and other parameters.
I need return string of DateTime. More this method is returning only null
receives an input string, convert to DateTime and i need put DateTime on valor.retorna_date_time string variable.
Code:
public void Search_DATE(string param_date)
{
SqlDataReader objReader;
SqlCommand objcmd = null;
vsql = "SELECT [IDCADASTRO],[RGP],[PEIXE],[PESO],[QUANTIDADE],[DATA_REGISTRO] FROM cadastro WHERE DATA_REGISTRO LIKE #DATA_REGISTRO";
if (this.Conectar())
{
try
{
DateTime dtParam = DateTime.Parse(param_date);
objcmd = new SqlCommand(vsql, objCon);
objcmd.Parameters.Add(new SqlParameter("#DATA_REGISTRO", dtParam));
objReader = objcmd.ExecuteReader();
if (objReader.Read())
{
valor.retorna_date_time = objReader.GetString(6);
}
}
catch (SqlException erro)
{
throw erro;
}
finally
{
this.Desconectar();
}
}
}
Input Parameters:
DateTime myDateTime = DateTime.Now;
string DateTimesql = myDateTime.ToString("dd-MM-yyyy");
objSQL.Search_DATE(DateTimesql);
valor.retorna_date_time is a global string variable.
Your SELECT statement returns 6 columns:
[IDCADASTRO],[RGP],[PEIXE],[PESO],[QUANTIDADE],[DATA_REGISTRO]
But IDatareader's GetString(n) method is 0-based, so GetString(6) returns the 7th column, which there isn't.
Change it to GetString(5).
Without seeing your table structure, I would try GetOrdinal.
Change
valor.retorna_date_time = objReader.GetString(6)
to
valor.retorna_date_time = objReader.GetOrdinal("DATA_REGISTRO");
Since you only seem to need just the last column, you can change your query to:
"SELECT [DATA_REGISTRO] FROM cadastro WHERE DATA_REGISTRO LIKE #DATA_REGISTRO";
And then read it using ExecuteScalar
objcmd = new SqlCommand(vsql, objCon);
objcmd.Parameters.AddWithValue("#DATA_REGISTRO", dtParam);
valor.retorna_date_time = objcmd.ExecuteScalar().ToString();
EDIT:
ExecuteScalar() will return a null reference if the query did not return anything.
You should check if it is null before converting it to string and passing it to valor.retorna_date_time. Do something like:
string returnValue = objcmd.ExecuteScalar() == null ?? String.Empty : objcmd.ExecuteScalar().ToString();
Basically if a parameter comes in as NULL, I want to send it to the database as a database NULL. As such (look at the comment inside the code below):
[HttpPost]
public void UpdateTitle(Title title)
{
string query = null;
string description = "";
string episodeAKA = "";
if (title.Description != null)
{
description = "'" + title.Description + "'";
}
else
{
//here's where description should be a DBNULL.
}
if (title.EpisodeAKA == null)
{
title.EpisodeAKA = "NULL";
}
myConnection.Open();
if (title.Operation == 'U')
{
query = "UPDATE dbo.AWD_Titles SET AwardStatusId = " + title.AwardStatus + ", Description = " + description + ", IsVerified = " + title.IsVerified + ", EpisodeAKA = '" + title.EpisodeAKA + "' WHERE AwardTitleId = " + title.AwardTitleId + " SELECT SCOPE_IDENTITY()";
}
var cmd = new SqlCommand(query, myConnection);
cmd.ExecuteScalar();
myConnection.Close();
}
}
And here's the class for Title:
public class Title
{
public int AwardTitleId
{
get;
set;
}
public int AwardStatus
{
get;
set;
}
public int IsVerified
{
get;
set;
}
public string EpisodeAKA
{
get;
set;
}
public string Description
{
get;
set;
}
public char Operation
{
get;
set;
}
}
The original code had several fundamental errors. This demonstrates how to do it right, including how to set DBNull:
[HttpPost]
public void UpdateTitle(Title title)
{
string query;
if (title.Operation == 'U')
{
query =
"UPDATE dbo.AWD_Titles" +
" SET AwardStatusId = #AwardStatusID , Description = #Description , IsVerified= #IsVerified , EpisodeAKA= #EpisodeAKA" +
" WHERE AwardTitleId= #AwardTitleId ;" +
" SELECT SCOPE_IDENTITY();";
} else {
query="";
//presumably you have a slightly different query string for inserts.
//Thankfully, they should have pretty much the same set of parameters.
//If this method will really only be called for updates, the code is quite a bit simpler
}
//instead of a shared myConnection object, use a shared connection string.
// .Net is set up so that you should be creating a new connection object for most queries.
// I know it sounds backwards, but that's really the right way to do it.
// Create the connection in a using(){} block, so that you guarantee it is
// disposed correctly, even if an exception is thrown.
using (var cn = new SqlConnection(myConnectionString))
using (var cmd = new SqlCommand(query, cn))
{
//guessing at database types, lengths here. Fix with actual column types
cmd.Parameters.Add("#AwardStatusId", SqlDbType.Int).Value = title.AwardStatus;
cmd.Parameters.Add("#Description", SqlDbType.NVarChar, 250).Value = title.Description;
cmd.Parameters.Add("#IsVerified", SqlDbType.Bit).Value = title.IsVerified;
cmd.Parameters.Add("#EpisodeAKA", SqlDbType.NVarChar, 100).Value = title.EpisodeAKA;
cmd.Parameters.Add("#AwardTitleId", SqlDbType.Int).Value = title.AwardTitleId;
//-------------
//This is the part that actually answers your question
foreach (var p in cmd.Parameters.Where(p => p.Value == null))
{
p.Value = DBNull.Value;
}
//-------------
cn.Open();
cmd.ExecuteScalar();
}
}
Well, with the code that you have, you could just use null in the SQL code:
description = "null";
However, you should really use a parameterised query instead of concatenating values into the SQL code. If any of the data comes from user input, your code is wide open to SQL injection attacks.
For a parameter value you use DBNull.Value for a null value, so the variable holding it has to be an object:
object description;
if (title.Description != null) {
description = title.Description;
} else {
description = DBNull.Value;
}
Now you can use that value in an SqlParameter object.
Ok, first things first. Your code is asking for a SQL injection attack. Use parameterized queries.
Unto the question itself. You need to pass the value DBNull.Value if what you want is a data base NULL. You could use a helper function that converts your string to the appropriate value.
private object ConvertToDbReadyString(string value)
{
if(value=="NULL")
return DBNull.Value;
else
return value;
}
if (title.Description != null)
{
description = "'" + title.Description + "'";
}
else
{
//here's where description should be a DBNULL.
}
try this one:
description = title.Description ?? string.Empty;
string variableValue == string.IsNullOrEmpty(stringValue) ? null : "Hello";
My table structure is as follows:
Session
--------------
SessionID (PK)
RoomID
SessionDate
SessionTimeStart
SessionTimeEnd
I have a following query which will always return one row and display in DGV. I use DataAdapter for connection:
DataTable queryResult = new DataTable();
string ConnStr = "Data Source=DUZY;Initial Catalog=AutoRegSQL;Integrated Security=True";
SqlConnection MyConn = new SqlConnection(ConnStr);
MyConn.Open();
//SQL query that returns todays sessions for the given roomID
string query = #"SELECT SessionID, RoomID, SessionDate, SessionTimeStart, SessionTimeEnd" +
" FROM [Session] " +
" WHERE RoomID = #RoomID " +
" AND SessionDate = cast(getdate() as date) ";
SqlCommand command = new SqlCommand(query, MyConn);
command.Parameters.Add("RoomID", SqlDbType.Char).Value = RoomID;
SqlDataAdapter adapter = new SqlDataAdapter(command);
adapter.Fill(queryResult);
I would like to save the query result into multiple strings representing table columns, i.e.
SessionIDstring = query result for SessionID column
RoomIDstring = query result for RoomID column
and so on...
Is it possible to achieve it using one query, or do I have to create 5 queries for each column?
Something similar to this, perhaps, using ADO.NET?
//SQL query that returns todays sessions for the given roomID
string query = #"SELECT SessionID, RoomID, SessionDate, SessionTimeStart, SessionTimeEnd" +
" FROM [Session] " +
" WHERE RoomID = #RoomID " +
" AND SessionDate = cast(getdate() as date) ";
using (var connection = new SqlConnection(ConnStr))
using (var command = new SqlCommand(query, connection))
{
command.Parameters.Add("RoomID", SqlDbType.Char).Value = RoomID;
try
{
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
if (reader.Read())
{
// Note that reader[x] has the equivalent type to the type
// of the returned column, converted using
// http://msdn.microsoft.com/en-us/library/cc716729.aspx
// .ToString() if the item isn't null is always ok
string SessionIDstring = reader[0].ToString(); // it should be an int
// reading it twice is ok
int RoomID = (int)reader[1]; // it should be an int
string RoomIDstring = reader[1].ToString(); // it should be an int
if (reader.Read())
{
throw new Exception("Too many rows");
}
}
else
{
throw new Exception("No rows");
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
This code was adapted from MSDN ADO.NET Code Examples. I added some usings and made it single row. I don't even want to know why MSDN examples don't go the full length with using.
Note that SqlDataAdapter are built to recover multiple rows/big data and put them in a DataSet. You can use them for single row data, but it's much easier to simply use a SqlDataReader if you only want to fill some variables.
declare #col1 int
declare #col2 varchar(42)
select #col1 = col1
, #col2 = col2
, ....
You could create a class like so...
public class SessionDto
{
public string SessionID {get; set;}
public string RoomID {get; set;}
public string SessionDate {get; set;}
public string SessionTimeStart {get; set;}
public string SessionTimeEnd {get; set;}
}
And then have a method that takes a Room ID and builds your session object
public SessionDto GetSessionData(int roomId)
{
using (var cnn = new SqlConnection(ConnStr))
{
SessionDto sessionDto;
string query = #"SELECT SessionID, RoomID, SessionDate, SessionTimeStart, SessionTimeEnd" +
" FROM [Session] " +
" WHERE RoomID = #RoomID " +
" AND SessionDate = cast(getdate() as date) ";
cnn.Open();
using (var cmd = new SqlCommand(query,cnn))
{
cmd.Parameters.Add("#RoomID", SqlDbType.Char).Value = roomId;
using (var rdr = cmd.ExecuteReader())
{
if (rdr.HasRows)
{
while (rdr.Read())
{
sessionDto = new sessionDto{
SessionID = rdr.GetString(0),
RoomID = rdr.GetString(1),
SessionDate = rdr.GetString(2),
SessionTimeStart = rdr.GetString(3),
SessionTimeEnd = rdr.GetString(4)
};
}
}
}
}
}
return sessionDto;
}
A lot of this is hand typed as I havent got access to VS right now,
but you should get it to work.
Also, I have used rdr.GetString(), there are other methods for GetType().