Handling null with dataset and LINQ - c#

I have a method which uses LINQ to look up a company in a local DataSet, using a company id (Guid). The properties from the data set is then stored in a class (CompanyModel), which is created for the occasion. One of the properties is the OrganizationNo, which is of type Long in the DataSet, but String in the CompanyModel.
The issue is, OrganizationNo can be null in the DataSet. This causes the ToString() method to throw an exception. I can tried fixing it (see below), but with no luck.
Isn't there some sort of simple, easy to read solution for this, which does not require multiple lines of code and/or use of try/catch?
UPDATE
The exception is thrown at an earlier point, since query becomes null if the organization number is null. Hence it has nothing to do with ToString() failing. The code never gets that far. I have tried changing the NullValue property of the OrganizationNo in the data table from (Throw Exception) to (Null), but this is not allowed. Is it a bad design we have chosen, using Long for a property which is sometimes null?
public void SelectCompany(Guid companyId)
{
SelectedCompany = new CompanyModel();
SelectedCompany.Id = companyId;
CompanyDataTabel dt = DataSet.Company;
// Look up the company in the company table in the data Set
var query = from company in dt.AsEnumerable()
where company.Id == companyId
select new
{
company.OrganizationNo,
company.Name,
company.PhoneNo,
company.Email,
};
// If the OrganizationNo is null, then the entire query is null.
// Hence the '.Count()' method will fail.
if (query.Count() != 1)
{
// One (and only one) company should match the organisation ID.
throw new ArgumentException("Multiple companies found.");
}
// These properties are never null and causes no issues
SelectedCompany.Name = query.First().Name;
SelectedCompany.PhoneNumber = query.First().PhoneNo;
SelectedCompany.EmailAddress = query.First().Email;
SelectedCompany.OrganisationNumber = query.First().OrganizationNo.ToString()
}

The problem in your query is that you are using a strongly typed DataSet which throws an error if you try to access a property that is null. To handle that case the DataSet automatically adds a bool method that you have to check before you access that nullable-column property. But your query creates an anonymous type that accesses this nullable property without this check. For that reason you will get the exception when the query is executed which is at query.First().
Use this query instead:
var query = from company in dt.AsEnumerable()
where company.Id == companyId
select new
{
OrganizationNo = company.IsOrganizationNoNull()
? string.Empty
: company.OrganizationNo.ToString(),
company.Name,
company.PhoneNo,
company.Email,
};
Side-note:
Instead of if (query.Count() != 1) you should use Single:
var company = query.Single(); // throws a desired exception if there are no or more than two records
SelectedCompany.Name = company.Name;
SelectedCompany.PhoneNumber = company.PhoneNo;
SelectedCompany.EmailAddress = company.Email;
SelectedCompany.OrganisationNumber = company.OrganizationNo;
This handles the case that there is none or more than one and will throw this exception on both cases. It's more efficient because you only need to execute the query once. Btw, all your query.First() calls must execute the whole query again

you can check OrganisationNumber property is must be define Nulable.. Nulable<long> or long? like this public long? OrganisationNumber {get;set;}
SelectedCompany.OrganisationNumber = string.Empty;
if(query.First() != null && query.First().OrganizationNo.HasValue)
{
SelectedCompany.OrganisationNumber =
query.First().OrganizationNo.Value.ToString();
}
or
SelectedCompany.OrganisationNumber = query.First() != null && query.First().OrganizationNo.HasValue ? "" : "";
or
SelectedCompany.OrganisationNumber =
query.First() != null ? query.First().OrganizationNo?.ToString() ?? string.Empty : string.Empty;

long type variable itself can not be null. but Nullable<long> can

The ?. operator works with null, which works for reference types or nullable value types, but not for normal value types like long.

Related

Handling null returns in new linq objects c#

What I'm going for? I need to post a newly created object to a db, the incoming object may have a null value. The created object is set to #nullible true where needed.
When data comes in and I land on a null string in my object I get a null reference and land on catch.
My code:
Objects.Data.Info.StoredData postData = new Objects.Data.Info.StoredData
{
Name = data.data.Name,
Type = data.data.Type,
Price = data.data.Price,
Indicator = data.data.Indicator,
Scan = data.data.Scan,
Comment = data.data.Extra
};
db.Information.Add(postData);
db.SaveChanges();
data.data.Extra can be null, sometimes.
I would usually write if statements to counter this, but don't feel like it's the best practice here. What direction should I go? I've checked a few other questions and msdn and can't find a clear path.
Thanks.
You can succinctly default to an empty string when the property is null by using the ?? operator, like so:
Comment = data.data.Extra ?? ""
//the value on the right is used if the expression on the left is null
?? is called the 'null-coalescing' operator: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-coalescing-operator
If you also want to handle the intermediate properties being null (which I don't think applies to this case but is good to know), and still want to default to an empty string, you can combine this with Eugene's suggestion of using ?. like so:
Comment = data?.data?.Extra ?? ""
?. is called the 'null-conditional' operator: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/member-access-operators#null-conditional-operators--and-
var postData = new Objects.Data.Info.StoredData
{
Name = data.data.Name,
Type = data.data.Type,
Price = data.data?.Price,
Indicator = data.data.Indicator,
Scan = data.data.Scan,
Comment = data.data.Extra
};
db.Entry(postData).State=EntityState.Added;
db.SaveChanges();
I thought that you have facing difficulty with Price attribute because this one is Not null in your db once your programming cursor over there it failed, so once you exactly do what I did then eventually you change this nullable and then easily check or insert on runtime.
You should use the Null Conditional Operator (?.), like this:
data?.data?.Name
This will prevent an NullReferenceException if data or data.data is null.

LINQ: Nullable object must have a value [duplicate]

There is paradox in the exception description:
Nullable object must have a value (?!)
This is the problem:
I have a DateTimeExtended class,
that has
{
DateTime? MyDataTime;
int? otherdata;
}
and a constructor
DateTimeExtended(DateTimeExtended myNewDT)
{
this.MyDateTime = myNewDT.MyDateTime.Value;
this.otherdata = myNewDT.otherdata;
}
running this code
DateTimeExtended res = new DateTimeExtended(oldDTE);
throws an InvalidOperationException with the message:
Nullable object must have a value.
myNewDT.MyDateTime.Value - is valid and contain a regular DateTime object.
What is the meaning of this message and what am I doing wrong?
Note that oldDTE is not null. I've removed the Value from myNewDT.MyDateTime but the same exception is thrown due to a generated setter.
You should change the line this.MyDateTime = myNewDT.MyDateTime.Value; to just this.MyDateTime = myNewDT.MyDateTime;
The exception you were receiving was thrown in the .Value property of the Nullable DateTime, as it is required to return a DateTime (since that's what the contract for .Value states), but it can't do so because there's no DateTime to return, so it throws an exception.
In general, it is a bad idea to blindly call .Value on a nullable type, unless you have some prior knowledge that that variable MUST contain a value (i.e. through a .HasValue check).
EDIT
Here's the code for DateTimeExtended that does not throw an exception:
class DateTimeExtended
{
public DateTime? MyDateTime;
public int? otherdata;
public DateTimeExtended() { }
public DateTimeExtended(DateTimeExtended other)
{
this.MyDateTime = other.MyDateTime;
this.otherdata = other.otherdata;
}
}
I tested it like this:
DateTimeExtended dt1 = new DateTimeExtended();
DateTimeExtended dt2 = new DateTimeExtended(dt1);
Adding the .Value on other.MyDateTime causes an exception. Removing it gets rid of the exception. I think you're looking in the wrong place.
When using LINQ extension methods (e.g. Select, Where), the lambda function might be converted to SQL that might not behave identically to your C# code. For instance, C#'s short-circuit evaluated && and || are converted to SQL's eager AND and OR. This can cause problems when you're checking for null in your lambda.
Example:
MyEnum? type = null;
Entities.Table.Where(a => type == null ||
a.type == (int)type).ToArray(); // Exception: Nullable object must have a value
Try dropping the .value
DateTimeExtended(DateTimeExtended myNewDT)
{
this.MyDateTime = myNewDT.MyDateTime;
this.otherdata = myNewDT.otherdata;
}
Assign the members directly without the .Value part:
DateTimeExtended(DateTimeExtended myNewDT)
{
this.MyDateTime = myNewDT.MyDateTime;
this.otherdata = myNewDT.otherdata;
}
In this case oldDTE is null, so when you try to access oldDTE.Value the InvalidOperationException is thrown since there is no value. In your example you can simply do:
this.MyDateTime = newDT.MyDateTime;
Looks like oldDTE.MyDateTime was null, so constructor tried to take it's Value - which threw.
I got this message when trying to access values of a null valued object.
sName = myObj.Name;
this will produce error. First you should check if object not null
if(myObj != null)
sName = myObj.Name;
This works.
I got this solution and it is working for me
if (myNewDT.MyDateTime == null)
{
myNewDT.MyDateTime = DateTime.Now();
}

inline If run all part of statements with out condition

I Have a method to get all Ticket with filtering by FromDate .
my code like this :
public List<Model.Ticket> SelectList(DateTime? fromDate = null)
{
db.Tickets.Where(row=> (!fromDate.HasValue || (fromDate.HasValue ? (row.Date.Date >= fromDate.Value.Date) : false));
}
but when pass null It returns an exception :
Nullable object must have a value.
what's wrong?
You need to get all Ticket with filtering by FromDate, But in your where condition will only return true or false acording to the formdate you are passing as a parameter.But where condition expect a logic to filter data from the table acording to.You have to modify your where condition as
where(ticket=>ticket.formDate--here what ever the condition you need to apply)
NB: For your lambda expression(
db.Tickets.Where(!fromDate.HasValue || (fromDate.HasValue ? (row.Date.Date >= fromDate.Value.Date) : false))
)
the db query will be
select * from Tickets where true/false--acording to the output
this won't work
Maybe in your object declaration you have to initialize it
Null to be initialized by using new keyword. As directly assigning null to certain object doesn't carry desired contents. Debugging still shows value to null but it can't be instantiated likewise.

Checking for null values in quickbooks using QBFC

I am trying to get the list of items inside of a quickbooks database. I have the following snippet of code:
IItemServiceRet itemServiceRet = itemRet.ItemServiceRet;
TestItem item = new TestItem();
item.Name = itemServiceRet.Name.GetValue();
item.Desc = itemServiceRet.ORSalesPurchase.SalesOrPurchase.Desc.GetValue();
item.Rate = itemServiceRet.ORSalesPurchase.SalesOrPurchase.ORPrice.Price.GetValue().ToString();
item.ItemType = "Service";
item.QBID = itemServiceRet.ListID.GetValue();
item.EditSeq = itemServiceRet.EditSequence.GetValue();
The code fails on the line:
item.Desc = itemServiceRet.ORSalesPurchase.SalesOrPurchase.Desc.GetValue();
"Object reference not set to an instance of an object"
Because that particular service item in the QB database does not have a description. I was curious if there was a 'clean' way to check for null values without having to have each line include an if statement checking if GetValue() returns null?
Edit: After trying Andrew Cooper's solution of:
item.Desc = itemServiceRet.ORSalesPurchase.SalesOrPurchase.Desc == null ? null : itemServiceRet.ORSalesPurchase.SalesOrPurchase.Desc.GetValue();
It still throws the exception:
Object reference not set to an instance of an object
Its as if GetValue() returns nothing at all if there is no description, which wouldn't make much sense.
You could use the ternary operator like this:
item.Desc = itemServiceRet.ORSalesPurchase.SalesOrPurchase.Desc == null ? null : itemServiceRet.ORSalesPurchase.SalesOrPurchase.Desc.GetValue();
But that's pretty ugly.
Best bet is to create a helper method that takes whatever type Desc and wraps the above logic.
I don't think there's any better solution, as you can't access the functions of a null object. I typically create a constructor for my items that does the checking so I only have to do that once. So in your example:
TestItem item = new TestItem(itemRet.ItemServiceRet);
The constructor would look like this:
public TestItem(IItemServiceRet i)
{
if(i.Name != null) this.Name = i.Name.GetValue();
if(i.ORSalesPurchase != null)
if(i.ORSalesPurchase.SalesOrPurchase != null)
{
if(i.ORSalesPurchase.SalesOrPurchase.Desc != null) this.Desc = i.ORSalesPurchase.SalesOrPurchase.Desc.GetValue();
if(i.ORSalesPurchase.SalesOrPurchase.ORPrice != null)
if(i.ORSalesPurchase.SalesOrPurchase.ORPrice.Price != null) this.Price = i.ORSalesPurchase.SalesOrPurchase.ORPrice.Price.GetValue();
}
}Keep in mind that this does work well for strings, as an empty string is usually the same as a blank field, but for number fields in QuickBooks this may cause problems. For example, an Invoice line can have a blank quantity field (which is a double). A double will default to the value of 0.0, but a blank quantity field in QuickBooks is treated as a quantity of 1.0. This can also cause problems with dates, as QuickBooks can have null date fields.

Pros and Cons of using "as", "is", "DBNull", ToString() in C#

When reading data from ExecuteReader. It returns me data in IDataReader. When I want to fill this data into my entities I will be assigning Non Nullable values in most of the cases to either Nullable types or Non Nullable types, e.g.:
int id;
string name;
int? age;
byte[] image;
example e = new example();
e.id = (int)dr["id"]; //unbox
e.name = dr["name"].ToString() //will result in empty string if dr["name"] is DBNull
e.name = dr["name"] is DBNull ? null : dr["name"].ToString();
e.age = dr["age"] as int?; // way 1
e.age = dr["age"] is DBNull ? null : (int?)dr["age"]; //way 2
e.image = dr["image"] as byte?;
EDIT
if id is primary key for the table and is NonNullable. But it is being used in another table where this key could be NULL then what should be the approach. Should that entity become NULL or exception should be thrown.
If the object reference is null, the is operator always returns false because there is no object available to check its type.
if (o is Employee) {
Employee e = (Employee) o;
// Use e within the ‘if’ statement.
}
The as operator works just like casting except the as operator will never throw an exception. Instead, if the object can’t be cast, the result is null.
Employee e = o as Employee;
if (e != null) {
// Use e within the ‘if’ statement.
}
Check more : C# is and as operators
If you're sure in result type and it can't be null:
(int)dr["id"]
If result can be null and you know the type:
dr["age"] as int?;
dr["age"] as int? ?? -1; // default value
If result can't be null and you don't know the type:
Convert.ToInt32(dr["age"]);
If result can be null and you don't know the type:
object age = dr["age"]; // can be short, int, etc
!Convert.IsDBNull(age) ? Convert.ToInt32(age) : -1;
My assignments would look as such:
e.id = (int)dr["id"]; //unbox
e.name = dr["name"] as string; // String if string, null if DbNull
e.age = dr["age"] as int?;
e.image = dr["image"] as byte?;
The as operator works best for reference types (such as strings or nullables), because it will return null should the object I'm casting be something else, like a DbNull. This is exactly the same as doing the check manually, but more terse and easy to understand.
Look at the answers to this question for some good examples of generic helper functions for your problem.
In (comments) you asked for more info on my dapper comment; the point I was trying to make is that this is essentially a solved problem, and there are a range of tools to help here, from the complex and feature-rich ORMs (NHibernate, Entity Framework, LLBLGenPro), through middle-grounds (LINQ-to-SQL etc), through to stupidly simple (but very effective) micro-ORMs (dapper-dot-net, Peta.Poco, Simple.Data).
dapper-dot-net is the (freely available, OSS) micro-ORM that underpins stackoverflow/stackexchange. It is based on the ridiculously simple approach of mapping directly from returned column names to member names (fields or properties), such that the usage is simply:
var connection = ... // an open connection
int id = ... // a record to fetch
var singleItem = connection.Query<example>(
"select * from example where id = #id", new {id}).Single();
or
int customerId = ...
var orders = connection.Query<Order>(
"select * from Orders where Status = 'Open' and CustomerId = #customerId",
new {customerId}).ToList();
where example is the type in your code, with members name, id, etc. It takes care of all the heavy lifting:
mapping inputs to parameters (see #id and #customerId, and how their values are provided)
materializing returned records into objects in a very optimised way
a few other tricks like horizontal multi-mapping, multi-grid mapping, automatic IN handling, etc
this means that you don't have to worry about details like null, DBNull, Nullable<T> etc, since dapper already handles all that for you, and is (thanks to some IL voodoo) just as fast at runtime as writing the materialization code yourself.

Categories