Error in linq query when using average - c#

I have two tables, picture and pictureratings in my database.
public partial class picture
{
public int idpicture { get; set; }
public int iduser { get; set; }
public string picTitle { get; set; }
public string picFilename { get; set; }
public System.DateTime pictime { get; set; }
public int nuditylevel { get; set; }
public int fakeslevel { get; set; }
// This property will hold the total accumulated/summed
// up rating of a picture
public int totalrating { get; set; }
}
public partial class pictureratings
{
public int idrating { get; set; }
public int idpictures { get; set; }
public int iduser { get; set; }
public System.DateTime iddatetime { get; set; }
public int iduserrateddby { get; set; }
public int rating { get; set; }
}
For every rating a new pictureratings row will be created. I want to group pictureratings table by the picture id and then count the likes. I want to show those likes in picture table in totalrating property.
So as per my now I am able to write the following code
var combo = from p in db.picturedetails
join l in db.picturelikes on p.idpictures equals l.idpictures into pl
select new LikesandPictureDetails
{
IdUserPic = p.iduser,
IdPicturess =p.idpictures,
Likes = p.likes,
NudityLevel = p.nuditylevel,
PicTitle = p.picTitle,
PicTime = p.pictime,
picFilename=p.picFilename,
Count=pl.Count(),
totalrating = pl.Average(c => c.likenumber) // This line is causing error
};
I am using web api to return query total. I am showing picture properties like iduser, picTitle, picFilename, pictime, nuditylevel and fakeslevel.
As per now every thing runs smooth, but when I add totalrating = pl.Average(c => c.likenumber) , I get an exception saying
The cast to value type 'Double' failed because the materialized value is null. Either the result type's generic parameter or the query must use a nullable type.
How to remove the error?

Maybe the problem is that pl has no records, try
replace
totalrating = pl.Average(c => c.likenumber) // This line is causing error
with
totalrating = pl.DefaulIfEmpty(0).Average(c => c.likenumber)

db.picturelikes.likenumber seems to be nullable? Can't find the property defined in your code though.
Anyways you can select all entries which are not null by putting
pl.Where(a=>a.likenumber != DBNull.Value /* or null whatever this is... */).Average...
If it is a nullable property:
pl.Where(a=>a.likenumber.HasValue).Average(a=>a.likenumber.Value)
:edit
I think .average returns a null-able decimal in this case. To assign it to your field, simply put
totalrating = pl.Average(c => c.likenumber)
Totalrating seems to be an int, eigther you'll loose some information by casting it down to an int, or you change the type to double...

The error appears to be that your DB has a column that can contain null values, yet your object has a non-nullable double type.
Does the query run if you select an anonymous type, instead of a concrete one?
ie. change this
select new LikesandPictureDetails
to
select new
If so, then you should change the type of a value in your target object to be nullable.

Related

Query using combobox selected object as parameter in Entity Framework

In a .NET Winforms application I'm trying to query using Entity Framework. I created Models with Db-Scaffold Database-First from SQL-Server in which i created all relationships.
Now combobox cb2 has Location as Datasource.
public partial class Location
{
public Location()
{
AktiveSchichten = new HashSet<AktiveSchichten>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<AktiveSchichten> AktiveSchichten { get; set; }
}
cb2's SelectedValue holds the LocationId. Now I'm trying to get every Shift in Shifts where location equals SelectedValue location.
public partial class Shifts
{
public int Id { get; set; }
public TimeSpan Start { get; set; }
public TimeSpan End { get; set; }
public int Location { get; set; }
public virtual Location LocationNavigation { get; set; }
}
}
My approach
var shifts = dbContext.AktiveSchichten.Where(a => a.Location = cb2.SelectedValue);
foreach (var shift in shifts)
{
//..
}
why can i not do this with an int when
var shifts = dbContext.Shifts.Where(a => a.Location == (int)cb2.SelectedValue);
doesnt throw an error
Your approach is syntactically incorrect: you have an assignment in the Where clause
a.Location = cb2.SelectedValue instead of a comparison
a.Location == cb2.SelectedValue
and you're not casting cb2.SelectedValue to an int (compared to the working statement var shifts =...).
Contrary to jdweng's comment casts will work with with LINQ - as long as the cast is valid (cb2.SelectedValue is of type object and holds an int). But you might be better off to assign the value before the LINQ statement:
var locationId = (int)cb2.SelectedValue;
var shifts = dbContext.Shifts.Where(a => a.Location == locationId);
Furthermore: Do you really have AktiveSchichten and Shifts on your dbContext? Maybe you would like to consolidate your naming (German, English; plural or singular for classes; class name for a property not representing an instance of the class Shifts.Location) to make your code easier to understand.

Get list of parent sub-type with all sub-type in LINQ

Using many Sub-Type tables with zero-one relation in C# code first!
public class MemberContractRelation
{
[Key]
public long Id { get; set; }
public long ContractId { get; set; }
public long MemberId { get; set; }
public long ListPrice { get; set; }
public decimal TaxCountryToPay { get; set; }
public decimal TaxProvinceToPay { get; set; }
public long InsuredCode { get; set; }
}
public class FamilyMemberContractSubtype : MemberContractRelation
{
public long CalculatedCheckupPrice { get; set; }
}
i want to getting list of my parent table (MemberContractRelation) with sub-type related record (like Left join) via this code :
var familyMemberContractSubtype = _rep.FamilyMemberContractSubtype.Where(a => a.Id == ContractId).Select(x => new
FamilyMemberInformationsBag
{
BirthDate = x.Member.BirthDate,
FirstName = x.Member.FirstName,
LastName = x.Member.LastName,
NationalID = x.Member.NationalCode,
PhoneNumber = x.Member.IranPhoneNumber,
Price = x.ListPrice,
ChekUpPrice = x.CalculatedCheckupPrice,
TotalPrice = x.ListPrice + x.CalculatedCheckupPrice + x.TaxProvinceToPay + x.TaxCountryToPay,
TaxProvinceToPay = x.TaxProvinceToPay,
TaxCountryToPay = x.TaxCountryToPay
}).ToList();
But it returns only records that have sub-Type and don`t return other records in MemberContractRelation!
I want to get a list of MemberContractRelation with sub-type and if it has not recorded in sub-type return Null value of property in sub-type!
remember I cant use any other solution for my project except above solution!
Assuming this is using EF TPT inheritance strategy (as it seems), first you should start the query from the parent (base) table:
// instead of _rep.FamilyMemberContractSubtype
// assuming _rep is DbContext
_rep.Set<MemberContractRelation>()
and then use operator as (important: not cast!) to access subtypes members, promoting non nullable types to nullable. In your sample:
ChekUpPrice = (long?)(x as FamilyMemberContractSubtype).CalculatedCheckupPrice
and
TotalPrice = x.ListPrice + x.TaxProvinceToPay + x.TaxCountryToPay +
((long?)(x as FamilyMemberContractSubtype).CalculatedCheckupPrice ?? 0)

How can I get a total count of an int field in a List?

I have this class, variable and method used to populate it:
public class CategoryGroupWordCountVM : ObservableProperty
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsToggled { get; set; }
public int TotalWordCount { get; set; }
}
List<CategoryGroupWordCountVM> categoryGroups;
categoryGroups = AS.dm.GetCategoryGroupWithWordCount();
How can I get a total of all of the values of the TotalWordCount field using LINQ or any other method if it can be done as a one liner. I know I can do this with a "for" loop but hoping for something that could be all in one line.
Use Linq,
var sum = categoryGroups.Sum(x=>x.TotalWordCount);
You can do LINQ to Objects and the use LINQ to calculate the totals:
decimal totalSum = (from od in categoryGroups
select od.TotalWordCount ).Sum();
You can also use lambda-expressions to do this, which is a bit "cleaner".
decimal totalSum = categoryGroups.Sum(x => x.TotalWordCount);

How to convert Collection of One Class type to Another Class Type collection in Entity Framework

I am working on Web Api where I would have to create Data Transfer Objects for displaying data on the UI of application.
I am working with Code First approach here is my Domain class
public class Employee
{
[Key]
public int BusinessEntityId { get; set; }
[Required]
[MaxLength(50)]
public string JobTitle { get; set; }
[Required]
[DataType(DataType.DateTime)]
public DateTime BirthDate { get; set; }
[Required]
[MaxLength(1)]
public string MaritalStatus { get; set; }
[Required]
[MaxLength(1)]
public string Gender { get; set; }
[Required]
[DataType(DataType.DateTime)]
public DateTime HireDate { get; set; }
[Required]
public Boolean SalariedFlag { get; set; }
public ICollection<EmployeePayHistory> PayHistories { get; set; }
}
Here is my Data Transfer Object(DTO) Class
public class EmployeePayHistoryListDTO
{
public int Id { get; set; }
public DateTime RateChangeDate { get; set; }
public Decimal Rate { get; set; }
public Int16 PayFrequency { get; set; }
public String JobTitle { get; set; }
public String Gendre { get; set; }
}
Now As PayHistories is collection in my Domain class I what i am doing is i am creating a new class
of which has collection of my DTO class type EmployeePayHistoryListDTO
public class EmployeeRelatedCollections
{
public ICollection<EmployeePayHistoryListDTO> PayHistories { get; set; }
}
So from my repository I am getting data correctly via following EF statement
_context.Employees.Include("PayHistories")
.Include("PayHistories")
.Single(e=>e.BusinessEntityId==id);
But where i am converting collection of my Employee class(Domain Class) to collection of my DTO type there i am getting error here is the code
PayHistories = (from ph in employee.PayHistories
select new EmployeePayHistoryListDTO
{
Id = ph.BusinessEntityId,
RateChangeDate = ph.RateChangeDate,
Rate = ph.Rate,
PayFrequency = ph.PayFrequency,
JobTitle = ph.Employee.JobTitle,
Gendre = ph.Employee.Gender
}).ToList();
I am getting following exception below is summary
System.NullReferenceException ,
Additional Information: Object reference Not set to an instance of an object.
Troubleshooting tips
1. Check to determine if the object is null before calling the method,
2. Use new keyword to create an object instance.
Looks like you failed to initialize your employee object. When the null reference exception occurs you should be able to check the value of the employee object by hovering your mouse on it and see that it is null. The nullreference exception occurs when you try to access a field on your null object (in this case, PayHistories).
See if this code avoids the exception:
if(employee!=null){
if(employee.PayHistories.Any()){
PayHistories = (from ph in employee.PayHistories
select new EmployeePayHistoryListDTO
{
Id = ph.BusinessEntityId,
RateChangeDate = ph.RateChangeDate,
Rate = ph.Rate,
PayFrequency = ph.PayFrequency,
JobTitle = ph.Employee.JobTitle,
Gendre = ph.Employee.Gender
}).ToList();
}
}
From:
PayHistories = (from ph in employee.PayHistories
select new EmployeePayHistoryListDTO
{
Id = ph.BusinessEntityId,
RateChangeDate = ph.RateChangeDate,
Rate = ph.Rate,
PayFrequency = ph.PayFrequency,
JobTitle = ph.Employee.JobTitle,
Gendre = ph.Employee.Gender
}).ToList();
Can you make it:
PayHistories = (from ph in employee.PayHistories
select new EmployeePayHistoryListDTO
{
Id = ph.BusinessEntityId,
RateChangeDate = ph.RateChangeDate,
Rate = ph.Rate,
PayFrequency = ph.PayFrequency
}).ToList();
and see if the exception still occurs?
It looks like based on that query you would have:
Employee -> PaymentHistory -> Employee.
In your statement:
_context.Employees.Include("PayHistories")
.Include("PayHistories")
.Single(e=>e.BusinessEntityId==id);
It doesn't look like you would include the additional employee object on top of your PayHistories (and did you intentially include it twice?). I believe you could also use a linq statement to get more strongly typed includes like
.Include(i => i.PayHistories)
Hopefully this will help you!
Make sure that employee.PayHistories does not contain null entries, or check it inside the query:
PayHistories = (from ph in employee.PayHistories where null != ph
etc. . .
Also, you're referring to a possibly lazy-loaded / uninitialized property on "ph" (Employee), which may also be null.
Here is how i solved my problem.I was having multiple references those were not loading properly.
There were two approaches
Approach 1.
The Include extension method overload which takes an Expression<Func<T,U>>
_context.Employees.Include("PayHistories.furtherreferencename").Include("PayHistories.furtherReference");
Approach 2.
Use Strongly typed Include method.
_context.Employees.Include(i=>i.PayHistories.select(e=>e.FurtherReference)).Include(i=>i.PayHistories.select(e=>e.FurtherReference));

Using a calculated value in the OrderBy clause with EF

I'm trying to use a calculated value in my OrderBy clause in a LINQ query.
The error I am getting is:
DbArithmeticExpression arguments must have a numeric common type.
My model looks like this:
public class PostModel
{
public int ID { get; set; }
public DateTime Created { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string FilePath { get; set; }
public float Rank { get; set; }
public UserProfile Creator { get; set; }
public bool ShowPost { get; set; }
public PostModel()
{
Created = DateTime.Now;
Rank = 0;
ShowPost = false;
}
}
and I'm trying to select posts using this:
var todaysDate = DateTime.Now.AddDays(-10);
var result = _database.Posts
.Where(p => p.ShowPost == true)
.OrderBy(x => ((float)x.Rank) - (((float)(x.Created - todaysDate).TotalDays)) / 2f)
.Skip(page * StaticVariables.ResponseDataPageSize)
.Take(StaticVariables.ResponseDataPageSize)
.Select(s => new
{
id = s.ID,
rank = s.Rank,
title = s.Title,
description = s.Description
}
);
It's the order by causing the error. I first thought it was that I was not casting all my variables to the same type, but adding (float) does not seem to help.
The purpose of the code is to make make high ranking posts fall down the list over time as to allow newer information to be shown.
Any ideas?
Use EntityFunctions in LinqToEntity:
EntityFunctions.DiffDays(todaysDate, x.Created)

Categories

Resources