I am reading a bunch of queries from a database. I had an issue with the queries not closing, so I added a CommandTimeout. Now, the individual queries read from the config file each time they are run.
How would I make the code cache the int from the config file only once using a static nullable and getter.
I was thinking of doing something along the lines of:
static int? var;
get{ var = null;
if (var.HasValue)
...(i dont know how to complete the rest)
My actual code:
private object QueryMethod(string item)
{
using (SqlConnection connection = new SqlConnection(item))
{
connection.Open();
using (SqlCommand sql = new SqlCommand())
{
AddSQLParms(sql);
sql.CommandTimeout = 30;
sql.CommandText = _cmdText;
sql.Connection = connection;
sql.CommandType = System.Data.CommandType.Text;
sql.ExecuteNonQuery();
}
connection.Close();
}
return false;
}
First: don't call it var !
Let's call it cached_value.
static int? cached_value;
get { return cached_value ?? cached_value = your_logic_here }
This way, the first time you call it, if it's null, it'll initialize the field. Next time you call the getter, you'll just get the value you need.
You could try something like this utilizing the Lazy<T> class:
public static class ConfigCache
{
private static Lazy<int> connectionTimeout =
new Lazy<int>(() => int.Parse(
ConfigurationManager.AppSettings["connectionTimeout"]));
public static int ConnectionTimeout
{
get { return connectionTimeout.Value; }
}
}
Usage:
sqlCmd.CommandTimeout = ConfigCache.ConnectionTimeout;
var is a system keyword - don't use it
V1 - in this version you expect config to have a value, otherwise error will occur
static int? _timeout = null;
private static int GetTimeout()
{
if (_timeout != null) return (int)_timeout;
_timeout = GetTimeoutFromConfig();
return (int)_timeout;
}
V2 - in this version you will use default value if config is empty
static int? _timeout = null;
private const int def_timeout = 120;
private static int GetTimeout()
{
if (_timeout != null) return (int)_timeout;
int? to = GetTimeoutFromConfig();
_timeout = (to ?? def_timeout);
return (int)_timeout;
}
converting from config
private int? GetTimeoutFromConfig()
{
int val;
bool converted = int.TryParse(ConfigurationManager.AppSettings["TimeoutValue"], out val);
return (converted ? val : null);
}
It sounds to be like you're asking how to use a Nullable variable.
static int? val;
get{
if (var.HasValue)
{
return val.Value;
}
else {
val = GetValFromConfig();
return val.Value;
}
}
var is a keyword in C#
Related
Let us suppose we have a class like below :-
class DoubleLinkedListNode
{
public int Value { get; set; }
public DoubleLinkedListNode(int value)
{
Value = value;
}
public DoubleLinkedListNode next = null;
public DoubleLinkedListNode prev = null;
}
And then we create a dictionary as given below :-
IDictionary<int, DoubleLinkedListNode> dict = new Dictionary<int, DoubleLinkedListNode>();
The key of the dictionary will hold the Value of the DoubleLinkedListNode that it contains like this :-
DoubleLinkedListNode newNode = new DoubleLinkedListNode(value);
dict.Add(newNode.Value, newNode );
Let us also create a function which takes the type of the value of the dictionary as input and we make that value null inside the body of the function as shown below :-
private void RemoveNode(DoubleLinkedListNode nodeToBeRemoved)
{
if(nodeToBeRemoved != null)
{
//Do Something
nodeToBeRemoved = null;
}
}
and we call the function like this :-
RemoveNode(dict[someValue]);
Let us create another function in which we make the value null explicitly as shown below :-
private void RemoveNodeAnother(DoubleLinkedListNode nodeToBeRemoved)
{
if(nodeToBeRemoved != null)
{
//Do Something
dict[nodeToBeRemoved.Value] = null;
}
}
And then we call the function like this :-
RemoveNodeAnother(dict[someValue]);
What is the difference between the above two functions ?
Why I am asking is this I was doing this question on Leetcode. The solution that I wrote is as follows :-
public class FirstUnique
{
private class DoubleLinkedListNode
{
public int Value { get; set; }
public DoubleLinkedListNode(int value)
{
Value = value;
}
public DoubleLinkedListNode next = null;
public DoubleLinkedListNode prev = null;
}
DoubleLinkedListNode dummyHeadNode = new DoubleLinkedListNode(-1);
DoubleLinkedListNode dummyTailNode = new DoubleLinkedListNode(-1);
IDictionary<int, DoubleLinkedListNode> dict = new Dictionary<int, DoubleLinkedListNode>();
public FirstUnique(int[] nums)
{
InitialiseDummyHeadAndTailNodes();
foreach(int i in nums)
{
Add(i);
}
}
public int ShowFirstUnique()
{
return dummyHeadNode.next.Value;
}
public void Add(int value)
{
if (dict.ContainsKey(value))
{
RemoveNode(dict[value]);
}
else
{
DoubleLinkedListNode newNode = new DoubleLinkedListNode(value);
AddNode(newNode);
}
}
private void InitialiseDummyHeadAndTailNodes()
{
dummyHeadNode.next = dummyTailNode;
dummyTailNode.prev = dummyHeadNode;
}
private void RemoveNode(DoubleLinkedListNode nodeToBeRemoved)
{
if(nodeToBeRemoved != null)
{
nodeToBeRemoved.prev.next = nodeToBeRemoved.next;
nodeToBeRemoved.next.prev = nodeToBeRemoved.prev;
// If I write nodeToBeRemoved = null, the solution won't pass.
// But if I write dict[nodeToBeRemoved.Value] = null, the solution is accepted.
dict[nodeToBeRemoved.Value] = null;
}
}
private void AddNode(DoubleLinkedListNode nodeToBeAdded)
{
//Update the pointers.
nodeToBeAdded.prev = dummyTailNode.prev;
nodeToBeAdded.prev.next = nodeToBeAdded;
nodeToBeAdded.next = dummyTailNode;
dummyTailNode.prev = nodeToBeAdded;
//Add the node to the dictionary.
dict.Add(nodeToBeAdded.Value, nodeToBeAdded);
}
}
I have made the comments where the anomaly lies. What could be the reason for this behavior ?
There is only one way to "set dictionary value to null" -
dictionary[key] = null;
indeed, if key is not there you need to add it first... Which leads to the way to set value to null -
if (dictionary.ContainsKey(key))
dictionary[key] = null;
else
dictionary.Add(key, null);
Note that setting value to null has zero impact on what was stored there previously.
I am trying to get some datetime values that are null in SQL to my C# application but i get some errors. One of the errors is:
'Unable to cast object of type 'System.DBNull' to type 'System.String'
Please, can someone tell me how to set a null DateTime value from SQL to my c# application?
I have already tried casting my C# variables to datetime value and string but both dont work. I've searched in stackoverflow but didn't found a solution for me.
I've also tried another solution but then i retrieved the date: '01/01/0001' as value instead of 'null'
public static List<Kamer> GetOpenstaandeBoekingen()
{
var result = new List<Kamer>();
using (var conn = new SqlConnection(ConnectionString))
{
conn.Open();
const string query = "select b.boekingid, k.naam, bk.incheckdatum, bk.uitcheckdatum, b.hotelid, b.aantal_gasten, bk.kamerid from boeking b join klant k on k.klantid = b.boekingid join boekingkamer bk on b.boekingid = bk.boekingid where bk.incheckdatum is null and bk.uitcheckdatum is null";
SqlCommand selectKamers = new SqlCommand(query, conn);
SqlDataReader reader = selectKamers.ExecuteReader();
while (reader.Read())
{
Kamer kamer = new Kamer((int)reader["boekingid"], (string)reader["naam"], (string)reader["incheckdatum"], (string)reader["uitcheckdatum"], (int)reader["hotelid"], (int)reader["aantal_gasten"], (int)reader["kamerid"]);
result.Add(kamer);
}
reader.Close();
}
return result;
}
And here is my class with the constructor:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FontysHotel
{
public class Kamer
{
// instantie variabelen
private int id;
private string naam;
private DateTime incheck_datum;
private DateTime uitcheck_datum;
private int hotel;
private int aantal_personen;
private int kamernr;
// properties
public int Id
{
get
{
return id;
}
set
{
id = value;
}
}
public string Naam
{
get
{
return naam;
}
set
{
naam = value;
}
}
public string Incheck_datum
{
get
{
return incheck_datum.ToShortDateString();
}
set
{
incheck_datum = Convert.ToDateTime(value);
}
}
public string Uitcheck_datum
{
get
{
return uitcheck_datum.ToShortDateString();
}
set
{
uitcheck_datum = Convert.ToDateTime(value);
}
}
public int Hotel
{
get
{
return hotel;
}
set
{
hotel = value;
}
}
public int Aantal_personen
{
get
{
return aantal_personen;
}
set
{
aantal_personen = value;
}
}
public int Kamernr
{
get
{
return kamernr;
}
set
{
kamernr = value;
}
}
public Kamer(int id, string naam, string incheck_datum, string uitcheck_datum, int hotel, int aantal_personen, int kamernr)
{
Id = id;
Naam = naam;
Incheck_datum = incheck_datum;
Uitcheck_datum = uitcheck_datum;
Hotel = hotel;
Aantal_personen = aantal_personen;
Kamernr = kamernr;
}
}
}
Uitcheckdatum and incheckdatum are the date values.
So i want, when i run the query is shows everything where are dates with null, it is for a hotel system and i want to show what bookings haven't checked in or out yet.
One way is to declare your DateTime variables as being a Nullable type, this is done by using the ? sign at the end such as this.
private DateTime? incheck_datum;
private DateTime? uitcheck_datum;
But it might be a better approach to look for, trap, and handle DB Nulls and then set default or min values like this
if (IsDBNullreader.IsDBNull(indexOfUitCheckDatum))
uitcheckdatum = DateTime.Minvalue;
else
uitcheckdatum = reader["uitcheckdatum"];
I would avoid direct initialization of an object without any previous check.
If you want to treat a DBNull value from the database as a null DateTime, there's no other option than declaring your two fields in the Kamer class using the nullable version DateTime? instead, since DateTime alone is a struct, a value type, which cannot be null. With that, you could do:
set
{
uitcheck_datum = string.IsNullOrEmpty(value) ? null : Convert.ToDateTime(value);
}
And in the loop:
while (reader.Read())
{
string incheckdatum = reader["incheckdatum"] as string;
string uitcheckdatum = reader["uitcheckdatum"] as string;
Kamer kamer = new Kamer((int)reader["boekingid"], (string)reader["naam"],
incheckdatum, uitcheckdatum, (int)reader["hotelid"],
(int)reader["aantal_gasten"], (int)reader["kamerid"]);
result.Add(kamer);
}
as saves you from possible casting exceptions. The indexer returns an instance of object. If it can't be cast to string, then null is returned.
In case you don't want to declare those fields as DateTime?, then just replace null in the set with a dummy date of your choice, e.g. DateTime.Now.
Also, make sure the string you receive from the database is a convertable string, or Convert will throw an exception. Maybe you'd want to add a try-catch to handle it.
I am using a session helper class to track more than several variable. So far I have 30 that are needed from page to page, not all at once of course. I need to convert some of the values from single to array. The Session helper class I use is as follows. For brevity I have shown only two session variables we use for tracking tab index for two accordions.
using System;
using System.Globalization;
using System.Linq;
using System.Web;
public class SessionHelper
{
//Session variable constants
public const string AccordionTop = "#tabTop";
public const string AccordionBot = "#tabBot";
public static T Read<T>(string variable)
{
object value = HttpContext.Current.Session[variable];
if (value == null)
return default(T);
else
return ((T)value);
}
public static void Write(string variable, object value)
{
HttpContext.Current.Session[variable] = value;
}
public static int TabTop
{
get
{
return Read<int>(AccordionTop);
}
set
{
Write(AccordionTop, value);
}
}
public static int TabBot
{
get
{
return Read<int>(AccordionBot);
}
set
{
Write(AccordionBot, value);
}
}
}
So on each page I can work with variables easily as follows:
To Write:
SessionHelper.TabTop = 1; or SessionHelper.TabBot = 3
To Read:
If (SessionHelper.TabTop……….)
This all works fine. I now want to extend this to array values held in session. The array contains int, string and date time value.
For the array session object I have tried adding:
public class SessionHelper
{
public const string CompInfo = "CompAccInfo";
public static T ReadArray<T>(string variable)
{
object[] result = HttpContext.Current.Session[variable] as object[];
if (result == null)
{
return default(T);
//result = new object[30];
}
else
return ((T)(object)result);
}
public static void WriteArray(string variable, object[] value)
{
HttpContext.Current.Session[variable] = value;
}
public static object[] CompDetails
{
get
{
return ReadArray<object[]>(CompInfo);
}
set
{
WriteArray(CompInfo, value);
}
}
}
But then I get an “Object reference not set to…… error when I try to do this:
public void EGetCompanyInformation(MasterPage myMaster, int entityCode)
{
int prevEntity = 0;Using (sqlconnetiooo
.....
//I get values here this works fine
//Then:
sqlr = cmd.ExecuteReader();
sqlr.Read();
if (sqlr.HasRows)
{
//Calculate accounting period adjustment.
yearEndDiff = 12 - Convert.ToInt32(sqlr.GetDateTime(5).Month);
//Company Code.
SessionHelper.CompDetails[0] = sqlr.GetInt32(0);
//Company Name.
SessionHelper.CompDetails[1] = sqlr.GetString(1);
//Currency Unit.
SessionHelper.CompDetails[2] = sqlr.GetString(2);
//Base Currency Code.
SessionHelper.CompDetails[3] = sqlr.GetString(3);
//Reporting Currency Code.
SessionHelper.CompDetails[4] = sqlr.GetString(4);
//Company Year End.
SessionHelper.CompDetails[5] = yearEndDiff;
//Country Code.
SessionHelper.CompDetails[6] = sqlr.GetString(6);
//Country Name.
SessionHelper.CompDetails[7] = sqlr.GetString(7);
//Base Currency Name.
SessionHelper.CompDetails[8] = sqlr.GetString(8);
//Report Currency Name.
SessionHelper.CompDetails[9] = sqlr.GetString(9);
//ClientID.
SessionHelper.CompDetails[10] = sqlr.GetInt32(10);
Other code here
}
}
It seems any SessionHelper.CompDetails[i] does not work : Error Object reference not set to an instance of an object.
What will happen if ReadArray will return default(T)? It will return null. Than access to any object by index inside the array will cause the exception you face.
It is not quite obvious what your code is intended to do.
SessionHelper.CompDetails[0] = sqlr.GetInt32(0);
What do you want here? CompDetails itself should return an array. But you are trying to rewrite it immediately by some values.
If you want to access the CompDetails and rewrite it's objects than you have to instantiate it by
int n = 10;
SessionHelper.CompDetails = new CompDetails[n];
default(object[]) will always throw null. because the array of object is reference type and default value of any reference type is null. So accessing null value will get you Object reference not set to an instance of object.
You can change your old implementation like below:
public static T Read<T>(string variable, int arraySize=10)
{
object value = HttpContext.Current.Session[variable];
if(typeof(T).IsArray && value == null)
{
//array requires size I personally prefer to have
//differnt read method for array.
return ((T)Activator.CreateInstance(typeof(T),arraySize));
}
if(!typeof(T).IsValueType && value == null)
{
//if it is not value type you can return new instance.
return ((T)Activator.CreateInstance(typeof(T)));
}
else if (value == null)
return default(T);
else
return ((T)value);
}
And access SessionHelper as below:
var sessionarray = SessionHelper.Read<object[]>("myarray",15);
....
// then use that sessionarray here.
....
You have to instantiate the CompDetails array before you start assigning values to it.
if (sqlr.HasRows)
{
//Calculate accounting period adjustment.
yearEndDiff = 12 - Convert.ToInt32(sqlr.GetDateTime(5).Month);
// Instantiate array
SessionHelper.CompDetails = new object[11];
//Company Code.
SessionHelper.CompDetails[0] = sqlr.GetInt32(0);
// etc
When writing code for existing applications, often times the development database environment does not match the production environment - and even worse, there are times still where overlaying the environments is just not an option.
One idea I had in mind to code for all environments would be to use a databound enum, whose values would be bound to the ID of the data item they represent. I couldn't get that to work with an Enum but I was able to solve it via abstract classes. For example:
public abstract class Colors
{
private static readonly string c_red = "red";
private static readonly string c_blue = "blue";
private static readonly string c_yellow = "yellow";
private static readonly string c_green = "green";
private static int? _red = null;
private static int? _blue = null;
private static int? _yellow = null;
private static int? _green = null;
public static int Red
{
get
{
if (_red == null)
_red = GetColorID(c_red);
return (int)_red;
}
}
public static int Blue
{
get
{
if (_blue == null)
_blue = GetColorID(c_blue);
return (int)_blue;
}
}
public static int Yellow
{
get
{
if (_yellow == null)
_yellow = GetColorID(c_yellow);
return (int)_yellow;
}
}
public static int Green
{
get
{
if (_green == null)
_green = GetColorID(c_green);
return (int)_green;
}
}
private static int GetColorID(string identifier)
{
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["Demo"].ConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand("spGetColorId", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("Name", identifier);
return Convert.ToInt32(cmd.ExecuteScalar());
}
}
}
}
By doing it this way, I'm able to call Colors.Red in this example to get the ID of Red regardless of if I'm in Dev, Testing, or Production.
My question is: is this really the ideal method of accomplishing this? Is there a native-to-C# method of databinding enums, or something equivalent to what I'm doing above?
Having an enum implies that the values are rarely, if ever, changes. you can think of it as a closed list of values (like days of the week etc.).
Because of this nature of enums, I find it acceptable to have this redundancy of having the enum underlying value being specified twice (once in the DB and the other in the enum itself).
If you are worried about discrepancies, you can run a validation for the values when your application starts and check that the values has the correct corresponding ids and that the number of values in the enum matches the number of values in the DB.
I have the following simple class to manage my SQL database operations
public class DatabaseManager
{
private string CommandString
{
set { CommandString = GetCommandString(commandtype); }
get { return CommandString; }
}
public string commandtype
{
set;
get;
}
public DatabaseManager(string commandtype)
{
commandtype = this.commandtype;
CommandString = GetCommandString(commandtype);
}
public DatabaseManager()
{
}
public static SqlConnection CreateConnection()
{
return new SqlConnection(Properties.Settings.Default.connectionString);
}
//returns a datatable if the command requires a dataadapter
public DataTable ExecuteSelect()
{
var x = new DataTable();
using (var da = new SqlDataAdapter(CommandString, DatabaseManager.CreateConnection()))
{
da.Fill(x);
}
return x;
}
private string GetCommandString(string commandtype)
{
switch (commandtype)
{
// select commands
case ("SELECTMARGINS"): CommandString = "select * from margins"; break;
case ("SELECTRANKS"): CommandString = "select * from ranks"; break;
/...and other commands
return CommandString;
}
}
i am getting a Stackoverflow exception on get { return CommandString; }
The get function is your problem
get { return CommandString; }
This is the morale equivalent of the following
public string GetCommandString() {
return GetCommandString();
}
This will just create infinite recursion and eventually a StackOverflowException will be thrown. You need to change the get and set to operate on a backing field which holds the actual value and use that instead
private string _commandString;
public string CommandString {
get { return _commandString; }
set { _commandString = GetCommandString(commandtype); }
}
You can't have a property return itself (it creates an infinite loop).
private string _CommandString;
public string CommandString
{
set { _CommandString = GetCommandString(commandtype); }
get { return _CommandString; }
}
You can't have a Get function return itself, it will just cause it to infinitely attempt to retrieve itself until the stack overflows.
Create a private variable to get and set to:
private string _CommandString;
private string CommandString
{
//Also you probably want to change commandtype to value, since you will be
//discarding whatever you attempt to set the variable as
set { _CommandString = GetCommandString(commandtype); }
get { return _CommandString; }
}
You cannot set or even get CommandString, you have to create a private variable in this case.
private string _commandString;
public string CommandString
{
set { _commandString = GetCommandString(commandtype); }
get { return _commandString; }
}
What is happening in your current code is that you are doing something like this:
CommandString = "x";
which calls
CommandString = GetCommandString(type);
which calls
CommandString = GetCommandString(type);
etc....so it keeps looping until it overflow. The private variable keeps you from setting the same property over and over again
Also, it looks like you are never actually using the value passed into the set function, which seems like a bug