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.
Related
I have a model in Entity Framework Core that goes something like this:
public class Anime
{
public int EpisodeCount { get { return Episodes.Count() } }
public virtual ICollection<Episode> Episodes { get; set; }
}
I'm having the issue of EpisodeCount being 0. The solution currently is to run a .Include(x => x.Episodes) within my EF query, but that loads the entire collection of episodes where it's not needed. This also increases my HTTP request time, from 100ms to 700ms which is just not good.
I'm not willing to sacrifice time for simple details, so is there a solution where I can have EF only query the COUNT of the episodes, without loading the entire collection in?
I was suggested to do this
var animeList = context.Anime.ToPagedList(1, 20);
animeList.ForEach(x => x.EpisodeCount = x.Episodes.Count());
return Json(animeList);
but this also returns 0 in EpisodeCount, so it's not a feasible solution.
You need to project the desired data into a special class (a.k.a. ViewModel, DTO etc.). Unfortunately (or not?), in order to avoid N + 1 queries the projection must not only include the count, but all other fields as well.
For instance:
Model:
public class Anime
{
public int Id { get; set; }
public string Name { get; set; }
// other properties...
public virtual ICollection<Episode> Episodes { get; set; }
}
ViewModel / DTO:
public class AnimeInfo
{
public int Id { get; set; }
public string Name { get; set; }
// other properties...
public int EpisodeCount { get; set; }
}
Then the following code:
var animeList = db.Anime.Select(a => new AnimeInfo
{
Id = a.Id,
Name = a.Name,
EpisodeCount = a.Episodes.Count()
})
.ToList();
produces the following single SQL query:
SELECT [a].[Id], [a].[Name], (
SELECT COUNT(*)
FROM [Episode] AS [e]
WHERE [a].[Id] = [e].[AnimeId]
) AS [EpisodeCount]
FROM [Anime] AS [a]
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)
Here's my model:
public class SeasonScore
{
[Key]
public int SeasonScoreID { get; set; }
[DisplayName("Season")]
public string season { get; set; }
[DisplayName("Year")]
public int year { get; set; }
[DisplayName("Value")]
public decimal value { get; set; }
[DisplayName("Subject")]
public virtual Subject Subject { get; set; }
}
public class Subject
{
[Key]
public int SubjectID { get; set; }
[DisplayName("Subject")]
public string subject { get; set; }
[DisplayName("Scores")]
public virtual List<SeasonScore> scores { get; set; }
public Subject()
{
scores = new List<SeasonScore>();
}
}
As you can see each instance of "Subject" contains a list of "SeasonScore". You can also see that SeasonScore has a decimal property called "value".
I have a database that stores a list of Subject objects. I want to find the largest "value" property from any of the SeasonScore instances contained within any of the Subject instances in my database.
I could do it the long way round, but I'm convinced I should be able to do it quickly using LINQ although I can't quite figure it out.
Assuming that your classes are properly mapped to database with LINQ2SQL or Entity Framework, you can retrieve max value using Max, like this:
var maxVal = dbContext
.Subjects
.Max(s => s.scores.Max(v => v.value));
or
var maxVal = dbContext
.Subjects
.SelectMany(s => s.scores)
.Max(v => v.value);
In both cases the query would be translated to SQL, and produce a single scalar entirely within RDBMS.
You can use the Enumerable.Max function. It has an overload which takes a selector. After you get a list of maximum values for each subject, call the Max function again to get the largest of those values.
subjects.Select(x => x.scores.Max(y => y.value)).Max();
See it in action here.
You can get a list of max value of each Subject's Score as:
IEnumerable<decimal> max = subjects.Select(a => a.scores.Max(b => b.value));
I have two models:
public class HouseType
{
public int Id { get; set; }
public string TypeName { get; set; }
public virtual IEnumerable<HouseModel> HouseModels { get; set; }
}
and
public class HouseModel
{
public int Id { get; set; }
public string ModelName { get; set; }
[DisplayFormat(DataFormatString = "{0:n2}")]
public double StandardPrice { get; set; }
[ForeignKey("HouseType")]
public int HouseTypeID { get; set; }
public virtual HouseType HouseType { get; set; }
public virtual IEnumerable<HouseUnit> HouseUnits { get; set; }
}
I am returning a JSON result, so as expected I cannot manipulate it in a view, because the display is handled by a javascript file that I made.
I am trying to retrieve the number of HouseModel that is contained by HouseType. I have tried:
db.HouseTypes.Select(h => new
{
HouseCount = h.HouseModels.Count()
}).ToList();
But Entity Framework complains about it. How can I access the count of related records inside an entity? Any help will be much appreciated. Thanks.
Use
public virtual ICollection<HouseUnit> HouseUnits { get; set; }
instead of
public virtual IEnumerable<HouseUnit> HouseUnits { get; set; }
Hope this helps.
Simply speaking, the trouble is that EF is trying to execute the .Select() statement on the db server but, of course, the db server does not know how to create a new object.
You first need to bring back the counts then create your objects so something like this should work better:
var listOfCounts = db.HouseTypes
.Select(h => h.HouseModels.Count())
.ToList()
.Select(c => new
{
HouseCount = c
})
.ToList();
in this example when the first .ToList() is executed the db needs only return a set of numbers (the counts of HouseModels in each HouseType) then we have a List<int> in local memory from which we can create our objects with the second Select statement.
As an aside...
It wasn't part of your original question but maybe you'd want to consider a dictionary rather than a list so you have some means of identifying which count of HouseModels belonged to each HouseType? in which case we could do something like:
Dictionary<int,string> houseModelCounts = db.HouseTypes
.ToDictionary(h => h.Id, h => h.HouseModels.Count());
which would give a dictionary keyed with the HouseType Id with values for the count of HouseModels in each type. I don't know your context though so maybe unnecessary for you?
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.