Error in selecting nullable using linq to Entities - c#

I am using linq to Entities. I am trying to select a nullable Int field with below code but I am getting Exception
List<MyClass> myList = myContext.Accounts
.Where(x => x.ACCOUNT_TYPE_ID == 58 && x.IS_DELETED == 0)
.Select(x=> new PayorCode
{
Id = x.ID,
Payor = x.CODE_NUM + " - "+ x.DESCRIPTION
}).ToList();
In Accounts property CODE_NUM is of Nullable<global::System.Int32> .
I am getting the below exception
Unable to cast the type 'System.Nullable`1' to type 'System.Object'. LINQ to Entities only supports casting EDM primitive or enumeration types.
How should I use the nullable field in Linq to Entites ? I tried with Convert.ToInt32 and object.Equals but both didn't worked.
Any help will be appreciated

Dealing with nullable ints in EF should be no different to dealing with them under normal circumstances. You can check that they have a value using .HasValue, you can read the value directly using .Value and you can null-coalesce using ??. Depending on what you want to happen in the case that this property is null, you should be able to do something along the lines of:
.Select(x=> new PayorCode
{
Id = x.ID,
Payor = x.CODE_NUM.HasValue
? x.CODE_NUM.Value + " - "+ x.DESCRIPTION
: "CODE_NUM Missing"
})
or perhaps:
.Select(x=> new PayorCode
{
Id = x.ID,
Payor = (x.CODE_NUM ?? "0") + " - "+ x.DESCRIPTION,
})

The class list "List" can't be used with the strongly type class list PayorCode referenced in your select. Either use a "var query = ..." along with PayorCode or if List is the same as PayorCode then substitute PayorCode with MyClass. So
.Select(x => new MyClass { ....}
Then answer 2 should work fine.

Related

Entity Framework passing array of integers to endpoint

I am passing an array of integers to an API endpoint composed in a model such as:
public class SomeModel {
public IList<int> ints { get; set; }
}
My endpoint to hit is:
Get["/myobjects/{id:int}"] = _ =>
{
var ints = this.Bind<SomeModel>();
return myService.someMethod1((int)_.id, ints.Ints));
};
Then, when I want to query the object in the DB,
var count = context.ReadOnly<SomeModel>()
.Query(x => x.myId == id && // id is already defined
ints != null &&
ints.Contains(x.SomeModelId))
.Select(x => x.Id)
.Count();
I am using Entity Framework as an ORM.
Unable to create a null constant value of type 'System.Collections.Generic.IList`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral]]'.
Or I get:
Cannot compare elements of type 'System.Collections.Generic.IList`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral]'. Only primitive types, enumeration types and entity types are supported.
Only entity types, enumeration types or primitive types are supported in this context.
The exception states that it can't create a null constant value, but I am populating the array that is coming in - so I don't understand why it is throwing this error.
EDIT: The array of ints is not being bound and the list is null. Does anybody know how to correctly bind to the list?
Have in mind all that checks you are doing in the lamdba are inside the query this means EF most probably will try to evaluate them to SQL.
But what you are checking is a variable that is not a part of the query. When the case is this, you need to split the check for null outside the query.
var query = context.ReadOnly<SomeModel>().Query(x => x.myId == id);
if (ints != null) {
query = query.Where(x => ints.Contains(x.SomeModelId);
}
var count = query.Select(x => x.Id).Count();
If I understood well the business case, if ints is null, the whole query will evaluate to false, so you most probably will be satisfied to just checking if ints is null -> if true, the count is zero. Otherwise - query the database.
var count = 0;
if (ints != null)
{
count = context.ReadOnly<SomeModel>()
.Query(x => x.myId == id &&
ints.Contains(x.SomeModelId))
.Select(x => x.Id)
.Count();
}

null issue during usage of count and sum LINQ

I have three tables and they are linked like
grandparent -> parent -> child
categoryType - > Categories - > Menus
when I try to run following
return categoryTypes.Select(x =>
new CategoryTypeIndexModel
{
Id = x.Id,
Name = x.Name,
Categories = x.Categories.Count,
Items = x.Categories.Sum(m => m.Menus.Count())
});
I get
The cast to value type 'System.Int32' failed because the materialized value is null. Either the result type's generic parameter or the query must use a nullable type.
You are trying to count something that isn't there when Categories is null.
I believe what Habib recommend would technically work but you would still have to account for a null value after the fact.
I think the better solution would be to account for it in your linq directly by looking for null and providing a default
return categoryTypes.Select(x => new CategoryTypeIndexModel
{
Id = x.Id,
Name = x.Name,
Categories = (x.Categories == null) ? 0 : x.Categories.Count,
Items = (x.Categories == null) ? 0 : x.Categories.Sum(m => m.Menus.Count())
});
If Menus could ever be null you would also need to account for that in a similar fashion

Linq error: The cast to value type 'Int32' failed because the materialized value is null

... But it's not null.
FYI - Many threads exist on this error, but none that I've seen using an anonymous type.
I'm Getting an odd InvalidOperationException in a Linq query.
message: "The cast to value type 'Int32' failed because the materialized value is null. Either the result type's generic parameter or the query must use a nullable type."
The confusing thing is that it's erroring when creating an anonymous type:
var workstepid = 484,449;
var wsData = ion.xWorkSteps
.Where(w => w.WorkStepId == workstepId)
.Select(w => new
{
w.WorkStepId,
w.ServiceId,
w.Service.TitleId,
w.Service.Title.OrderId,
w.Service.Title.AltTitleId
}).SingleOrDefault();
In LinqPad this particular query runs just fine and the workstepId used returns an integer value for each property of the anonymous type. So why a casting error when there is no null value for any property!?
FYI, the last property AltTitleId is a nullable int, and the other properties are ints.
Also, this code was written weeks ago and I didn't get this error until today. Is something funky w/ my EF?
Edit: SOLVED
We use soft-delete in our db's, setting deleted records to Acive=0.
It turns out that there is a property set in EF on the edmx tables filtering out inactive records (filter for Active=1). Naturally, this wouldn't effect Linqpad which gives me the expected result, but since this was an older record I was testing, the title record (Service.Title) had been marked Active=0 and was therefore returning null.
Thanks to everyone for the help.
var workstepid = 484,449;
var wsData = ion.xWorkSteps
.Where(w => w.WorkStepId == workstepId)
.Select(w => new
{
w.WorkStepId.Value,
w.ServiceId.Value,
w.Service.TitleId.Value,
w.Service.Title.OrderId.Value,
w.Service.Title.AltTitleId.Value
}).SingleOrDefault();
Hi you need to add .Value in your int data type to accept null value. hope this helps
If w.WorkStepId is nullable, try setting your variable as...
int? workstepid = 484449;
I suppose, the problem is in your SingleOrDefault().
I suppose that you get 0 records:
var workstepid = 484,449;
var len = ion.xWorkSteps
.Where(w => w.WorkStepId == workstepId)
.Length();
And then the anonymouse type must be replace by Default (this is what SingleOrDefault do), but there is no default for your anonymous type.
Try to change it to:
var wsData = ion.xWorkSteps
.Where(w => w.WorkStepId == workstepId)
.Select(w => new
{
w.WorkStepId,
w.ServiceId,
w.Service.TitleId,
w.Service.Title.OrderId,
w.Service.Title.AltTitleId
})
.Take(1)
.ToArray();
May be there are no Service/Title/Order id somewhere, but if it declared as int anonymous type expect int (not nullable), but from database it returns null.
Try to rewrite as :
var workstepid = 484,449;
var wsData = ion.xWorkSteps
.Where(w => w.WorkStepId == workstepId)
.Select(w => new
{
WorkStepId = (int?)w.WorkStepId,
ServiceId = (int?)w.ServiceId,
TitleId = (int?)w.Service.TitleId,
OrderId = (int?)w.Service.Title.OrderId,
w.Service.Title.AltTitleId
}).SingleOrDefault();

Comparing a nullable column throws "Unable to cast the type..." exception

My entity NewsItem has a nullable foreign key property: LibraryID of type int?.
My issue is when I query the property and compare it with any value except null, I get exceptions.
Initially my code was:
int? lid = ...
var results = context.NewsItems
.Where(n => n.LibraryID == lid);
but it gives me no results at all, no matter what lid is.
So, I tried:
var results = context.NewsItems
.Where(n => n.LibraryID.Equals(lid));
gives exception:
Unable to create a constant value of type 'System.Object'. Only primitive types or enumeration types are supported in this context.
and then I tried:
var results = context.NewsItems
.Where(n => lid.Equals(n.LibraryID));
and got:
Unable to cast the type 'System.Nullable`1' to type 'System.Object'. LINQ to Entities only supports casting EDM primitive or enumeration types.
and this:
var results = context.NewsItems
.Where(n => object.Equals(lid, n.LibraryID));
gives same exception as the last one.
Now I was desperate, so I tried to complicate stuff (like other forums suggested, for example here):
var results = context.NewsItems
.Where(n => (lid == null ? n.LibraryID == null : n.LibraryID == lid));
but still getting same exception.
So... any SIMPLE workarounds?
How about
var results = context.NewsItems
.Where(n => lid.HasValue ? lid.Value == n.LibraryId.Value : (!n.LibraryId.HasValue) );
Hmm, that first snippet should work. I've used nullables like that many times. First thing I'd do is a sanity check just to make sure LibraryID is really int? and not long? or similar.
Other than that, you can try this:
var results = context.NewsItems
.Where(n => (lid.HasValue ? n.LibraryID == lid.Value : !n.LibraryID.HasValue));
Or to avoid the ?: within the query:
var results = lid.HasValue
? context.NewsItems.Where(n => n.LibraryID == lid.Value)
: context.NewsItems.Where(n => !n.LibraryID.HasValue);
It seems that EF does not find the correct operator overload. Therefore it produces wrong results if you set lid = null.
Use linq to objects by adding AsEnumerable() to your query and everything is fine:
var results = context.NewsItems.AsEnumeryble().Where(n => n.LibraryID == lid);
According to the MSDN docs (which I finally found), .Where() will only filter your collection. If you want to see if there are actually results, resolve by lazily executing the filtered query with .ToList(), GetEnumerator, or enumerating the collection with foreach;
This method is implemented by using deferred execution. The immediate
return value is an object that stores all the information that is
required to perform the action. The query represented by this method
is not executed until the object is enumerated either by calling its
GetEnumerator method directly or by using foreach in Visual C# or For
Each in Visual Basic.
http://msdn.microsoft.com/en-us/library/bb534803.aspx
int? lid = ...
var results = context.NewsItems
.Where(n => n.LibraryID == lid).ToList();
var results = context.NewsItems
.Where(n => n.LibraryID.HasValue && n.LibraryID.Value == lid.Value );
edit:
Previous filter was based on my understanding that you wanted to filter to entires having a particular value. Updated will filter to null or value.
var results = context.NewsItems
.Where(n => !n.LibraryID.HasValue || n.LibraryID.Value == lid.Value );

Linq To Entities Query

Consider the following Query :
var profilelst =
(
from i in dbContext.ProspectProfiles
where i.CreateId == currentUser
select new ProspectProfile
{
ProspectId = i.ProspectId,
Live = i.Live,
Name = i.Name,
ServiceETA = i.Opportunities.OrderByDescending(t => t.FollowUpDate)
.FirstOrDefault()
.ServiceETA.ToString(),
FollowUpDate = i.Opportunities.OrderByDescending(t => t.FollowUpDate)
.FirstOrDefault()
.FollowUpDate
}
)
.ToList();
return profilelst.OrderByDescending(c=>c.FollowUpDate)
.Skip(0).Take(endIndex)
.ToList();
Here in this query please take a look at FollowUpDate and ServiceType, these both i have fetched from Opportunity table, is there any other work around to get these both..
One to Many Relationship in tables is like: ProspectProfile -> Opportunities
Whether the query i have written is ok or is there any another work around that can be done in easier way.
The only thing you can improve is to avoid ordering twice by changing your code to this:
var profilelst
= dbContext.ProspectProfiles
.Where(i => i.CreateId == currentUser)
.Select(i =>
{
var opportunity
= i.Opportunities
.OrderByDescending(t => t.FollowUpDate)
.First();
return new ProspectProfile
{
ProspectId = i.ProspectId,
Live = i.Live,
Name = i.Name,
ServiceETA = opportunity.ServiceETA.ToString(),
FollowUpDate = opportunity.FollowUpDate
}
}).ToList();
return profilelst.OrderByDescending(c => c.FollowUpDate).Take(endIndex).ToList();
I made several changes to your original query:
I changed it to use method chains syntax. It is just so much easier to read in my opinion.
I removed the unnecessary Skip(0).
The biggest change is in the Select part:
I changed FirstOrDefault to First, because you are accessing the properties of the return value anyway. This will throw a descriptive exception if no opportunity exists. That's better than what you had: In your case it would throw a NullReferenceException. That's bad, NullReferenceExceptions always indicate a bug in your program and are not descriptive at all.
I moved the part that selects the opportunity out of the initializer, so we need to do the sorting only once instead of twice.
There are quite a few problems in your query:
You cannot project into an entity (select new ProspectProfile). LINQ to Entities only supports projections into anonymous types (select new) or other types which are not part of your entity data model (select new MySpecialType)
ToString() for a numeric or DateTime type is not supported in LINQ to Entities (ServiceETA.ToString())
FirstOrDefault().ServiceETA (or FollowUpdate) will throw an exception if the Opportunities collection is empty and ServiceETA is a non-nullable value type (such as DateTime) because EF cannot materialize any value into such a variable.
Using .ToList() after your first query will execute the query in the database and load the full result. Your later Take happens in memory on the full list, not in the database. (You effectively load the whole result list from the database into memory and then throw away all objects except the first you have Takeen.
To resolve all four problems you can try the following:
var profilelst = dbContext.ProspectProfiles
.Where(p => p.CreateId == currentUser)
.Select(p => new
{
ProspectId = p.ProspectId,
Live = p.Live,
Name = p.Name,
LastOpportunity = p.Opportunities
.OrderByDescending(o => o.FollowUpDate)
.Select(o => new
{
ServiceETA = o.ServiceETA,
FollowUpDate = o.FollowUpDate
})
.FirstOrDefault()
})
.OrderByDescending(x => x.LastOpportunity.FollowUpDate)
.Skip(startIndex) // can be removed if startIndex is 0
.Take(endIndex)
.ToList();
This will give you a list of anonymous objects. If you need the result in a list of your entity ProspectProfile you must copy the values after this query. Note that LastOpportunity can be null in the result if a ProspectProfile has no Opportunities.

Categories

Resources