Linq: Nullable Object must have Value - linq

My query is as follows:
int ID = db.Q_Table.Find(item.PassedInID).ID;
I already found a solution for my issue, however i am wondering why i must write it like so
1.
Nullable(int) ID = db.Q_Table.Find(item.PassedInID).ID;
2.
db.Q_Table.Where(w => w.PassedInID== item.PassedInID).Select(s => s.ID ).SingleOrDefault();
It wouldn't let me put int int he < in the above code -.-...
I am curious why i have to code it to a nullable int? I really didn't want to code it like 2nd solution because its more code :). Yes i have made sure there are values in the database and from the below image you can see my database doesn't accept nulls.
Thanks for any answers

There is a difference between int and Nullable<int> or int?, you can't directly assign a Nullable<int> to int (Nullable<T>), Consider:
int? x = 123;
int y = x; //This would be an error
But you can use null-coalescing operator
int? x = 123;
int y = x ?? 0;
Now for your case, your ID seems to be a mapped to column in database which allows null. That will map to C# Nullable<int>, if you want to assign the result to an int you can do:
int ID = db.Q_Table.Find(item.PassedInID).ID ?? 0;
That will give your variable the value of ID or 0 if it is null.

ID is not an int but rather a Nullable<int> (or short form int?).
This is typically the case when the underlying database column is nullable.
There is also no < operator defined on an int?. If you want to do that, you have to check for the presence of a value first:
db.Q_Table.Where(w => w.PassedInID.HasValue && w.PassedInID.Value == item.PassedInID)
.Select(s => s.ID ).SingleOrDefault();

that's probably because db.Q_Table.Find returns a nullible int.
you can probably also do the following if you wanted to
int? ID = db.Q_Table.Find(item.PassedInID).ID;

I guess you could do something like the following, it is a little less code:
int? t;
int ID = (t = db.Q_Table.Find(item.PassedInID).ID) == null ? -1 : t;
Of course, now you will have to handle -1 ID as a special case later in your code. I expect you just want a nullable int.

Related

How to take elements from the same collection based on other atrributes

Hi I have a collection of objects:
MyClasss{
int Id,
int ?OtherId
}
I want to take do sth like:
collection.Where(x.Id == y.OtherId).
Ho to perform it in linq?
I think you're looking for:
collection.Where(x => collection.Any(y => x.Id == y.OtherId));
Be aware that this will also pull out ones where the OtherId is equal to the Id on the same object.
I think your problem is that Id is an int, while OtherId is a nullable int.
You have a sequence of objects of MyClass, and you want to keep only those objects where "Id equals OtherId". Or to be precise:
Keep only those objects where OtherId is not null, and OtherId == Id.
The easiest method would be:
IEnumerable<MyClass> myCollection = ...
IEnumerable<MyClass> result = myCollection
.Where(myClass => myClass.OtherId.HasValue && myClass.Value == myClass.Id);

Getting a column by string name

I'm trying to update a record given the customer Id, the row Id, and a dynamic column name.
Thus far I have the following, with the trouble spot marked by ***:
public void UpdateRecord(int Id, string rval, string column, string value)
{
var rId = GetRvalId(rval);
var entry = _context.Customers
.Where(x => x.Id == Id && x.RVals.Id == rId && x.***column?*** == column).First();
entry = value;
}
I haven't been able to find a good example of how to do this.
Addition after comments at the end
The reason you couldn't find examples is because it is not a good design.
Your method is very error prone, difficult to test and horrible to maintain. What if someone types the incorrect column name? What if you try to assign a string to the customer's birthday? And even if you would implement some string checking for column names and proposed values, then your program wouldn't work anymore after someone changes the names or the types of the columns.
So let's redesign!
Apparently you have a Customer with an Id and a property Rvals. This property Rvals also has a property Id.
You also have a function GetRValId that can convert a string rval to an int rvalId.
What you want, is given an Id and a string rval, you want to update one of the columns of the first Customer with this Idand rValId.
Side questions: Can there be more than one Customer with Id? In that case: are you sure Id is an ID? What do you want if there are more matching Customers? Update all customers or update only the first one? Which customer do you define as the first customer?
Leaving the side questions aside. We want a function signature that reports errors at compile time if you use non-existing customer properties, or if you try to assign a string to a Birthday. Something like this perhaps?
Update the name of the customer:
int customerId = ...
string rval = ...
string proposedName = "John Doe";
UpdateCustomerRecord(id, rval, customer => customer.Name = proposedName);
Update the Birthday of the customer:
DateTime proposedBirthday = ...
UpdateCustomerRecord(id, rval, customer => customer.Birthday = proposedBirthday)
This way you can't use any column that does not exist, and you can't assign a string to a DateTime.
You want to change two values in one call? Go ahead:
UpdateCustomerRecord(id, rval, customer =>
{
customer.Name = ...;
customer.Birthday = ...;
});
Convinced? Let's write the function:
public void UpdateCustomerRecord(int customerId, string rval, Action<Customer> action)
{
// the beginning is as in your function:
var rId = GetRvalId(rval);
// get the customer that you want to update:
using (var _Context = ...)
{
// get the customer you want to update:
var customerToUpdate = _Context.Customers
.Where(customer => customer.Id == Id
&& customer.RVals.Id == rId)
.FirstOrDefault();
// TODO: exception if there is no customerToUpdate
// perform the action and save the changes
action(customerToUpdate);
_context.SaveChanges();
}
Simple comme bonjour!
Addition after comments
So what does this function do? As long as you don't call it, it does nothing. But when you call it, it fetches a customer, performs the Action on the Customer you provided in the call, and finally calls SaveChanges.
It doesn't do this with every Customer, no it does this only with the Customer with Id equal to the provided Id and customer.RVals.Id == ... (are you still certain there is more than one customer with this Id? If there is only one, why check for RVals.Id?)
So the caller not only has to provide the Id, and the RVal, which define the Customer to update, but he also has to define what must be done with this customer.
This definition takes the form of:
customer =>
{
customer.Name = X;
customer.BirthDay = Y;
}
Well if you want, you can use other identifiers than customer, but it means the same:
x => {x.Name = X; x.BirthDay = Y;}
Because you put it on the place of the Action parameter in the call to UpdateCustomerRecord, I know that x is of type Customer.
The Acton statement means: given a customer that must be updated, what must we do with the customer? You can read it as if it was a Function:
void Action(Customer customer)
{
customer.Name = ...
customer.BirthDay = ...
}
In the end it will do something like:
Customer customerToUpdate = ...
customerToUpdate.Name = X;
customerToUpdate.BirthDay = Y;
SaveChanges();
So in the third parameter, called Action you can type anything you want, even call functions that have nothing to do with Customers (probably not wise). You have an input parameter of which you are certain that it is a Customer.
See my earlier examples of calling UpdateCustomerRecord, one final example:
UpdateCustomerRecord( GetCustomerId(), GetCustomerRVal,
// 3rd parameter: the actions to perform once we got the customerToUpdate:
customer =>
{
DateTime minDate = GetEarliestBirthDay();
if (customer.BirthDay < minDate)
{ // this Customer is old
customer.DoThingsThatOldPeopleDo();
}
else
{ // this Customer is young
customer.DoThingsThatYoungPeopleDo();
}
}
}
So the Action parameter is just a simpler way to say: "once you've got the Customer that must be updated, please perform this function with the Customer
So if you only want to update a given property of the customer write something like:
UpdateCustomerRecord(... , customer =>
{
Customer.PropertyThatMustBeUpdated = NewValueOfProperty;
}
Of course this only works if you know which property must be updated. But since you wrote "I am trying to update a specific cell." I assume you know which property the cells in this column represent.
It is not possible to pass the column name as the string value in LINQ. Alternate way to do it, if you have the limited number of the column name which can be passed then it can be achieved as below:
public void UpdateRecord(int Id, string rval, string column, string value)
{
var rId = GetRvalId(rval);
var entry = _context.Customers
.Where(x => x.Id == Id &&
x.RVals.Id == rId &&
(x.column1 == value || column == column1) &&
(x.column2 == value || column == column2) &&
(x.column3 == value || column == column3) &&
(x.column4 == value || column == column4) &&
(x.column5 == value || column == column5) &&
)).First();
entry = value;
}
UpdateRecord(5, "rval", "column1", "value");
UpdateRecord(5, "rval", "column2", "value");
UpdateRecord(5, "rval", "column3", "value");
Here, suppose you have the 5 columns that can be passed while calling the funcion UpdateRecord then you can add the 5 clauses in the WHERE as above.
Other way to do it dynamic LINQ
var entry = db.Customers.Where(column + " = " + value).Select(...);

Linq 2 SQL Sum using lambda and handling nulls

When using sum with lambda in Linq to SQL using the following code:
int query = (from f in odc.RDetails
where f.ticketID == int.Parse(ticket.ToString())
select f).Sum(x => x.Rate);
I get the following error:
The null value cannot be assigned to a member with type System.Int32 which is a non-nullable value type.
. You have to make sure x.Rate is an int, and not an int? (an int that accepts null as a value).
. If the query has no elements, .Sum won't do anything and will return null. Choose a default value, let's say 0.
var query = from f in odc.RDetails
where f.ticketID == int.Parse(ticket.ToString())
select f;
int result = query.Any()
? query.Sum(x => x.Rate ?? 0) // use the ?? if x.Rate is an "int?".
: 0; // default value you can choose.
I would break the int.Parse(ticket.ToString()) onto its own line to isolate that parse from the Linq for debugging.
We don't know whether that is throwing the exception or if one of the RDetails.Rate values is null. Is it indeed a Nullable<int>?
If RDetails.Rate is a Nullable<int>, then you could ...Sum(x => x.Rate ?? 0) and avoid the exception.

LINQ query result in int type variable

I want the the LINQ query result in int type variable.
i have a query this will always return the single int value. i want result sumthing like that.
int interlineId = from cSInterline in codeShareInterline_.AsEnumerable()
where cSInterline.Field<int>("InterCodeId") == interCodeId[0]
select cSInterline.Field<int>("PermitedPercent");
But it returning the error..
Your query is returning an IEnumerable<int>, with only one item in this case. So add Single or SingleOrDefault onto the end to return only that 1 item. If your query might return more than 1 item then use FirstOrDefault.
int interlineId =
(from cSInterline in codeShareInterline_.AsEnumerable()
where cSInterline.Field<int>("InterCodeId") == interCodeId[0]
select cSInterline.Field<int>("PermitedPercent")).SingleOrDefault();
Try this:
int interlineId = (from cSInterline in codeShareInterline_.AsEnumerable()
where cSInterline.Field<int>("InterCodeId") == interCodeId[0]
select cSInterline).Single().Field<int>("InterCodeId");
Try this (it should work):
int? interlineId = (from cSInterline in codeShareInterline_.AsEnumerable()
where cSInterline.Field<int>("InterCodeId") == interCodeId[0]
select cSInterline.Field<int>("PermitedPercent")).FirstOrDefault();

how do I pass null to int column in linq

How do we assign null value to int column in LINQ.
eg.
SQLDBDataContext sqlD = new SQLDBDataContext();
var result = from p in sqlD.loadsRadius(Convert.ToInt32(Request["radius"]), .....
here if Request["radius"] is null gives an error.
I could pass 0 via this but I need to change in many already existing procedures.
Thanks in advance.
Anil
You need to case the int to a null, eg:
var result = from p in sqlD.loadsRadius(string.IsNullOrEmpty(Request["radius"]) ? (int?)null : int.Parse(Request["radius"]);
If the exception is a FormatException, my guess is that the value returned by Request["radius"] is actually the string "null". If Request["radius"] actually returned null, Convert.ToInt32() would return zero. You may try using using int.TryParse() to avoid the exception.
as suggested by Codechef..
int radius = -1;
int.TryParse(Request["radius"],out radius)
if(radius > 0) // you can remove this clause if you don't want this
{
SQLDBDataContext sqlD = new SQLDBDataContext();
var result = from p in sqlD.loadsRadius(radius)
}
Look into nullable types: Here.
You could use ?? operator like this:
Convert.ToInt32(Request["radius"] ?? "0")
If Request["radius"] equals to null, it will return "0" instead.

Resources