I wrote a generic method to retrieve single values from database (MSSQL Server).I encountered into a case that I need to get a Boolean value from DB.
As you can see in the code below, a Object local field (IsExist) gets the result.
When the value in DB is False GenericScalar() method return False (as it should)
and the condition: if (IsExist == null) in GetWanLineDisconnectionData() is true and the return block is executing, even though IsExist is False and not null.
Why is that?
How can I overcome this problem?
private void GetWanLineDisconnectionData()
{
string q = "SELECT WanLineDiscconection FROM AdditionalProjectsData WHERE SpCall= " + "'" + spCall + "'";
object IsExist = Orange.ProjectManagment.DAL.Database.GenericScalar<object>(q);
if (IsExist == null) {
return;
}
if (bool.Parse(IsExist) == true) {
RadWanDiscYes.Checked = true;
} else {
RadWanDiscNo.Checked = true;
}
}
Database method:
public static T GenericScalar<T>(string query)
{
OleDbConnection connection = new OleDbConnection(sqlConnString);
connection.Open();
OleDbCommand cmd = new OleDbCommand(query, connection);
try
{
var result = cmd.ExecuteScalar();
if (result == null)
{
return default(T);
}
else
{
return (T)result;
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
CloseConnection(ref connection);
}
}
EDIT:
maybe a few screen shoots will better demonstrate it:
(note that: GetWanLineDisconnectionData() is written in VB.NET and GenericScalar() is written in C# on a different project in the solution):
in the beginning IsExist is nothing (null).
the query finds one row and the value of the bool column WanLineDiscconection is false and IsExist is set to false as it should be.
here is the problem, the program enters the if block and IsExist is not nothing (null).
The variable foo in object foo = false is definitely not null, so the premise in your title is incorrect.
ExecuteScalar() returns null when there are no rows. In that case, the method GenericScalar() return default(T), which for object will be null.
How to solve this depends on what your data looks like. You probably want to represent the result in a nullable int, or int? instead of object:
var exists = Orange.ProjectManagment.DAL.Database.GenericScalar<int?>(q);
RadWanDiscYes.Checked = exists.GetValueOrDefault() > 0;
See How does GetValueOrDefault work?, What is the default value of the nullable type "int?" (including question mark)?.
Aside from that: you generally also don't want to write handy wrappers around database queries, because you're reinventing the wheel poorly, opening up your application to SQL injection. That being said, there's a lot more going wrong in that method, including but not limited to not disposing your database connection and rethrowing exceptions without their stacktrace.
You´re mixing compile-time and runtime information. Whilst GenericScalar<object>(q) is an information that exists at compile-time the type returned from ExecuteScalar at compile-time is just object. You expect it to be of type boolean, which might or might not be true for your specific case. However this is not relevant to the compiler.
In short that means that T actually is object, not whatever you expect it to be from your database. And as CodeCaster allready mentioned the default-value for object is just null.
Si I´d suggest to use GenericScalar<bool> instead of GenericScalar<object> because you seem to know what your query actually returns - in your case a bool. Then default(T) evaluates to false, not to null.
Related
Consider the following code snippet
public class Class1
{
public enum TestEnum
{
Value1 = 1,
Value2 = 2
}
public void TestCall()
{
/*some standard DB code returning an SqlDataReader...*/
SqlDataReader rdr = com.ExecuteReader();
Item item = new Item();
/*original code*/
/*Database "Type" is a varchar() field containing an integer, please dont ask why :)*/
if (rdr["Type"].GetType() == typeof(DBNull))
{
item.Type = TestEnum.Value1;
}
else if ((string)rdr["Type"] == "1")
{
item.Type = TestEnum.Value2;
}
else if ((string)rdr["Type"] == "2")
{
item.Type = TestEnum.Value1;
}
else
{
item.Type = TestEnum.Value1;
}
/*suggested code*/
item.Type = rdr["Type"] as TestEnum? ?? TestEnum.Value1; //<- default / null value to use
}
}
public class Item
{
public Class1.TestEnum Type;
}
During code review, a colleague of mine pointed out that i could replace the cascading IFs ("original code") with a single line ("suggested code")
While the suggested code runs just fine, I get a NullReferenceException when inspecting "rdr["Type"] as TestEnum?" at debug time.
I was wondering if this is a sign of underlying problems with the suggested code, what is the prefered way of mapping a database value to an enum, and what are your thoughts on this kind of code generally speaking.
The suggested code is just wrong - it will not throw exception, but will always evaluate to TestEnum.Value1.
Why? The reader returns the value as object. The as T? operator will evaluate to non null value only if the object represents a boxed T value. When the object contains string as in your case, or even if was a boxed int (the underlying type of your enum), still the operator as TestEnum? will evaluate to null, hence the expression will hit the ?? TestEnum.Value1 condition.
Shortly, don't rely on such tricks. If you want to improve that code, create a method (which can be reused from other places if needed):
static TestEnum ToTestEnum(object dbValue)
{
TestEnum value;
return Enum.TryParse(dbValue as string, out value) ? value : TestEnum.Value1;
}
and then change the original code like
item.Type = ToTestEnum(rdr["Type"]);
Right now I am working on a simple program, and this is a problem I've been thinking over many times. Many times I run my methods twice because of checking on the return value before running them, and I would like to know if there is a way I can prevent this, like using the returned value from the method I am checking against. It's quite hard to explain so here is a real life example from my program.
public class SFDBRepository
{
public static Domain.SF.SFObject GetSFOrder(string WorkOrd)
{
//As you can see here i'm checking on the output of this method, before trying to return it.
if (Domain.SF.SF.GetOrder(WorkOrd) != null)
{
//If the value is not null (My method returns null if no result), return the object
return Domain.SF.SF.GetOrder(WorkOrd);
}
//Same thing happens here. My method runs twice every time almost.
else if(Domain.Building_DeliveryPerformance.Building_DeliveryPerformance.GetObject(WorkOrd) != null)
{
return Domain.Building_DeliveryPerformance.Building_DeliveryPerformance.GetObject(WorkOrd);
}
else
{
return null;
}
}
}
You can simplify this down to the following code, which will only call those methods once and make the code much more readable:
public class ShopFloorDBRepository
{
public static Domain.ShopFloor.ShopFloorObject GetShopFloorOrder(string workOrd)
{
return Domain.ShopFloor.Shopfloor.GetOrder(workOrd) ??
Domain.DG9_DeliveryPerformance.DG9_DeliveryPerformance.GetObject(workOrd);
}
}
To explain why this works - the ?? operator (the null-coalescing operator!) basically says "if the returned value on the left hand side of the ?? is null, then return the value of the expression on the right hand side".
This way you only need to call your functions once.
public static Domain.ShopFloor.ShopFloorObject GetShopFloorOrder(string WorkOrd)
{
//As you can see here i'm checking on the output of this method, before trying to return it.
Domain.ShopFloor.ShopFloorObject wo = Domain.ShopFloor.Shopfloor.GetOrder(WorkOrd);
if (wo != null)
{
//If the value is not null (My method returns null if no result), return the object
return wo;
}
//Same thing happens here. My method runs twice every time almost.
Domain.ShopFloor.ShopFloorObject yowo = Domain.DG9_DeliveryPerformance.DG9_DeliveryPerformance.GetObject(WorkOrd);
if(yowo != null)
{
return yowo;
}
/* default return */
return null;
}
PS
You're kinda doing the "Factory Pattern"
See
http://www.dofactory.com/net/factory-method-design-pattern
Looks to me like you could be using a temporary variable to hold the result, which you can test and return.
public class ShopFloorDBRepository
{
public static Domain.ShopFloor.ShopFloorObject GetShopFloorOrder(string WorkOrd)
{
var result = Domain.ShopFloor.GetOrder(WorkOrd);
if (result != null) return result;
...
This is a common paradigm, especially when the method being called is expensive and/or has side effects you don't wish to incur twice.
Here, the "var" declaration sets the type of "result" to the type returned by the method being called; you could also use the name of the actual type.
If you wish to make two different kinds of tests like this, you'll need two different variables unless they have the same type (which in this case it appears they do).
An alternate mechanism that does require the full type, that you'll also see:
public static ShopFloorObject GetShopFloorOrder(string WorkOrd)
{
ShopFloorObject result;
if ( (result = Domain.ShopFloor.GetOrder(WorkOrd)) != null )
return result;
if ( (result = Domain.DG9_DeliveryPerformance.DG9_DeliveryPerformance.GetObject(WorkOrd)) != null)
return result;
return null;
Here you're explicitly declaring the type of the return value, then making the two calls you've indicated, testing the results against null, and returning the first non-null value.
I have a SQL CLR aggregate function which sporadically throws a System.NullReferenceException exception when executed against the same dataset. The purpose of the custom aggregate is to:
Return latest(x, y) where x is a DATETIME column and y is an INTEGER column.
The value for column y for the most recent value of column x will be returned.
The dataset being hit by the query is a subset of 142,145 rows of a 2,931,563 row table, with the aggregation resulting in (when it runs) 141,654 rows being returned.
The code for the CLR aggregate function is as follows:
using System.Data.SqlTypes;
using System.Runtime.InteropServices;
using Microsoft.SqlServer.Server;
[StructLayout(LayoutKind.Sequential)]
[SqlUserDefinedAggregate(Format.Native, IsInvariantToDuplicates = true, IsInvariantToNulls = true, IsInvariantToOrder = true, IsNullIfEmpty = true, Name = "Latest")]
public class Latest
{
private SqlDateTime latestDateTime;
private SqlInt32 latestValue;
public void Init()
{
latestDateTime = SqlDateTime.Null;
latestValue = SqlInt32.Null;
}
public void Accumulate(SqlDateTime recordDateTime, SqlInt32 value)
{
if (latestDateTime.IsNull)
{
latestDateTime = recordDateTime;
latestValue = value;
}
else
{
if (recordDateTime > latestDateTime)
{
latestDateTime = recordDateTime;
latestValue = value;
}
}
}
public void Merge(Latest value)
{
if ((value.latestDateTime < latestDateTime) || (latestDateTime.IsNull))
{
latestValue = value.latestValue;
latestDateTime = value.latestDateTime;
}
}
public SqlInt32 Terminate()
{
return latestValue;
}
};
As far as I can tell there's nowhere in the function that can result in a null reference, assuming that SQL server is following the contract outlined on MSDN (though it's much more likely I'm wrong than SQL Server!). So in short, what am I missing here?
To clarify:
I believe I've met the requirements of the contract for a SqlUserDefinedAggregate (all required methods implemented)
The code initialises all member variables in the Init method (again part of the contract implementation) to ensure that if SQL re-uses (as it's permitted to) an instance of the aggregate for a different group it's cleaned down and non-null
Clearly I've missed a nuance of the contract that I'm expected to meet as I can see no reason for the NullReferenceException to be thrown. What have I missed?
This may turn out not to be the answer, but as I need to include code, I won't post it as a comment.
Having a NULL value for value.latestDateTime wouldn't cause this error. You only get the NULLReferenceException when an OBJECT is null, and you try to refer to it (by accessing it's properties for instance).
The only place in your code where I see you referencing an object is in the Merge void. The object is value which is of type Latest.
I know you say it's not theoretically possible for value to ever be null, but that can't be proven or disproven in the code you've posted since Merge is public and therefore accessed from other applications.
I have found in OOP that it's safest to ALWAYS null-check any object before referencing it. All you have to do is change your Merge code to this (if my c# memory serves...if my syntax is off, I'm sure you'll get the idea):
public void Merge(Latest value)
{
if (value != null)
{
if ((value.latestDateTime < latestDateTime) || (latestDateTime.IsNull))
{
latestValue = value.latestValue;
latestDateTime = value.latestDateTime;
}
}
}
It's up to you if you want to do something else when value IS null. But this makes this stretch of code absolutely safe from NullReferenceExceptions, rather than trusting to "theoretically shouldn't be possible", which almost always means "IS possible" ; )
Everything does appear to be correct. Except for possibly one thing. Can either of the source columns for the two input parameters be NULL? The code itself does seem to handle NULLs. However, if there are NULLs in the data then I think you have the IsInvariantToNulls property of the SqlUserDefinedAggregate attribute set incorrectly as it should be false since a NULL in either field could affect the result.
Also:
The datatype of the field being used for recordDateTime is DATETIME and not DATETIME2, correct?
Try running the query after adding OPTION(MAXDOP 1) as a query hint as that should prevent the Merge method from being called and that can help narrow down the issue. If the exception never happens with OPTION(MAXDOP 1) then it most likely has to do with the Merge method. But if it still occurs, then it most likely has nothing to do with the Merge method.
To clarify some questioning of how SqlDateTime handles comparison operators (i.e. the < and >) when .IsNull is true: it is handled properly and will return a false if either side of those operators has .IsNull == true.
I would also remove the [StructLayout(LayoutKind.Sequential)] decorator. The default .NET handling should be fine.
I would add explicit check for NULL:
public void Accumulate(SqlDateTime recordDateTime, SqlInt32 value)
{
if (latestDateTime.IsNull)
{
latestDateTime = recordDateTime;
latestValue = value;
}
else
{
if (!recordDateTime.IsNull)
{
if (recordDateTime > latestDateTime)
{
latestDateTime = recordDateTime;
latestValue = value;
}
}
}
}
Besides, your logic in Merge seems wrong... I'd repeat the same code as in Accumulate:
public void Merge(Latest value)
{
if (latestDateTime.IsNull)
{
latestDateTime = value.latestDateTime;
latestValue = value.latestValue;
}
else
{
if (!value.latestDateTime.IsNull)
{
if (value.latestDateTime > latestDateTime)
{
latestDateTime = value.latestDateTime;
latestValue = value.latestValue;
}
}
}
}
I'm getting the error "Cannot implicitly convert type 'int?' to 'int'. An explicit conversion exists (are you missing a cast?)" on my OrdersPerHour at the return line. I'm not sure why because my C# skills are not that advanced. Any help would be appreciated.
static int OrdersPerHour(string User)
{
int? OrdersPerHour;
OleDbConnection conn = new OleDbConnection(strAccessConn);
DateTime curTime = DateTime.Now;
try
{
string query = "SELECT COUNT(ControlNumber) FROM Log WHERE DateChanged > #" + curTime.AddHours(-1) + "# AND User = '" + User + "' AND Log.EndStatus in ('Needs Review', 'Check Search', 'Vision Delivery', 'CA Review', '1TSI To Be Delivered');";
OleDbCommand dbcommand = new OleDbCommand(query, conn);
dbcommand.Connection.Open();
dbcommand.CommandType = CommandType.Text;
OrdersPerHour = (int?)dbcommand.ExecuteScalar();
Console.WriteLine("Orders per hour for " + User + " is " + OrdersPerHour);
}
catch (OleDbException ex)
{
}
finally
{
conn.Close();
}
return OrdersPerHour;
}
Well you're casting OrdersPerHour to an int?
OrdersPerHour = (int?)dbcommand.ExecuteScalar();
Yet your method signature is int:
static int OrdersPerHour(string User)
The two have to match.
Also a quick suggestion -> Use parameters in your query, something like:
string query = "SELECT COUNT(ControlNumber) FROM Log WHERE DateChanged > ? AND User = ? AND Log.EndStatus in ('Needs Review', 'Check Search', 'Vision Delivery', 'CA Review', '1TSI To Be Delivered')";
OleDbCommand dbcommand = new OleDbCommand(query, conn);
dbcommand.Parameters.Add(curTime.AddHours(-1));
dbcommand.Parameters.Add(User);
this is because the return type of your method is int and OrdersPerHour is int? (nullable) , you can solve this by returning its value like below:
return OrdersPerHour.Value
also check if its not null to avoid exception like as below:
if(OrdersPerHour != null)
{
return OrdersPerHour.Value;
}
else
{
return 0; // depends on your choice
}
but in this case you will have to return some other value in the else part or after the if part otherwise compiler will flag an error that not all paths of code return value.
Int32 OrdersPerHour = 0;
OrdersPerHour = Convert.ToInt32(dbcommand.ExecuteScalar());
The first problem encountered with your code is the message
Local variable OrdersPerHour might not be initialized before accessing.
It happens because in the case where your database query would throw an exception, the value might not be set to something (you have an empty catch clause).
To fix this, set the value to what you'd want to have if the query fails, which is probably 0 :
int? OrdersPerHour = 0;
Once this is fixed, now there's the error you're posting about. This happens because your method signature declares you are returning an int, but you are in fact returning a nullable int, int?, variable.
So to get the int part of your int?, you can use the .Value property:
return OrdersPerHour.Value;
However, if you declared your OrdersPerHour to be null at start instead of 0, the value can be null so a proper validation before returning is probably needed (Throw a more specific exception, for example).
To do so, you can use the HasValue property to be sure you're having a value before returning it:
if (OrdersPerHour.HasValue){
return OrdersPerHour.Value;
}
else{
// Handle the case here
}
As a side note, since you're coding in C# it would be better if you followed C#'s conventions. Your parameter and variables should be in camelCase, not PascalCase. So User and OrdersPerHour would be user and ordersPerHour.
Check the declaration of your variable. It must be like that
public Nullable<int> x {get; set;}
public Nullable<int> y {get; set;}
public Nullable<int> z {get { return x*y;} }
I hope it is useful for you
You can change the last line to following (assuming you want to return 0 when there is nothing in db):
return OrdersPerHour == null ? 0 : OrdersPerHour.Value;
Your method's return type is int and you're trying to return an int?.
OrdersPerHour = (int?)dbcommand.ExecuteScalar();
This statement should be typed as,
OrdersPerHour = (int)dbcommand.ExecuteScalar();
If you're concerned with the possible null return value, you can also run something like this:
int ordersPerHour; // can't be int? as it's different from method signature
// ... do stuff ... //
ordersPerHour = (dbcommand.ExecuteScalar() as int?).GetValueOrDefault();
This way you'll deal with the potential unexpected results and can also provide a default value to the expression, by entering .GetValueOrDefault(-1) or something more meaningful to you.
simple
(i == null) ? i.Value : 0;
I have a method private static DataTable ParseTable(HtmlNode table) and sometimes this method has no return value then I want to make return value optional, is it possible ?
I have tried with if condition.But there is error.
How can I make return value optional for the method if possible ?
You can't make the return value optional.
Your two options are to either return a null or an empty DataTable:
return new DataTable();
OR:
return null;
Which one is right? It depends on your application logic and how much null checking you are willing to do in your calling functions.
Update: (following comment)
This is how to return conditionally (assumes a variable called dataTable):
if(gotTable)
{
return dataTable;
}
else
{
return null;
}
That's what null is for. Your method may return no object by returning null.
Keep in mind that returning null may complicate matters for the callers as they must check for null before using the returned reference, so in some cases it may be better to return a Null Object.
You could always return null to indicate that there is no meaningful return value.
If your method is called ParseTable and it fails "Parse" a "Table", then it should throw an exception. The advantage of this is that the exception can give the caller information about why it couldn't parse (html was invalid, unexpected column etc). The problem with returning null is that an unexpected nullreference exception almost never tells you the cause of the problem.
The "right" way to make a method that tries to parse a table, but happily does nothing if no result could be found is:
public bool TryParseTable(HtmlNode table, out DataTable result){
// your code...
if(success)
{
result = //the table you parsed
return true;
}
else
{
result = null;
return false;
}
}
Ok, so "result" could be null after calling this method, but at least the caller is more inclined to use an if statement thanks to the return type and method name.
private static void ParseTable(HtmlNode table, out DataTable data)
{
// do the parse, fill bool gotTable
data = gotTable ? new DataTable() : null;
}
private static void ParseTable(HtmlNode table)
{
ParseTable(table, out null);
}
if caller need table
DataTable data;
ParseTable(table, out data);
if not
ParseTable(table);
EDIT: I can't find how to implement optional out/ref parameters. So maybe it's impossible until .NET 4.0 or fully impossible.