Get entity with all its child which meet a certain condition - c#

Just a disclaimer, this might have been already asked, but I didn't really knew what to search for.
So basically I have the following model:
public class Car
{
public int Id { get; set; }
public string UniqueName { get; set; }
public List<Feature> Features { get; set; }
}
public class Feature
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
Lets say I want to get a car which's UniqueName equals Bentle, but only with Features which cost less then 100$.
I could do something like this:
var car = DbContext.Cars.FirstOrDefault(x=> x.UniqueName == "Bentle");
car.Features = car.Features.Where(x=> x.Price <= 100).ToList();
This indeed works, but it seems to me as a lot of unnecessary conversions. Is there any way to shorten this Query?
A few Requirements:
I need the Car Entity itself
The List of Features only contain Features which cost less then 100$

Although I don't see any unnecessary conversion in your query, but you can try the following if you want to execute your request in one line:
var car = DbContext.Cars.Where(x=> x.UniqueName == "Bentle").Select(car =>
new Car()
{
Features = car.Features.Where(x=> x.Price <= 100),
.
.
/*here copy the remaining properties of car object*/
}).FirstOrDefault();

Related

Determine if all items in ICollection<T> are not contained in List<T> using Linq query

so this is the setup:
Rule Model
public class Rule
{
public int RuleId { get; set; }
public BillOfMaterial BillOfMaterial { get; set; }
public ICollection<Option> MustNotContainAllOptions { get; set; }
}
Option Model
public class Option
{
public int OptionId { get; set; }
public string OptionCode { get; set; }
public ICollection<Rule> MustNotContainAllRules { get; set; }
}
I am trying to query a rule for its bill of materials from a given base and list of options. The only condition at this point is that the rule can't contain any of a given list of options.
Example Input
Input Options: PA,PB
Example Rule
Rule: MustNotContainOptions = PA, Bill Of Material = BOM1
In this case the query should return nothing since the input has option PA
What I have tried
OptionList = The input list of options
var MustNotContainAnyQuery = (from rule in db.Rules
where rule.MustNotContainAllOptions.Any(option => !OptionList.Contains(option.OptionCode))
select rule.BillOfMaterial.BomNumber);
and
var MustNotContainAnyQuery = (from rule in db.Rules
where rule.MustNotContainAllOptions.All(option => !OptionList.Contains(option.OptionCode))
select rule.BillOfMaterial.BomNumber);
I can't seem to lock this down. If someone could explain what I am doing wrong that would be a great help.
Thank you
If OptionList is a list of Options, contains will not work on the optioncode.
You could do this if theyre the same reference or properly implemented valuetypes:
!OptionList.Contains(option)
or this if not:
!OptionList.Any(opt => opt.OptionCode == option.OptionCode)
your first query is wrong, you could change it to this...
where !rule.MustNotContainAllOptions.Any(option => OptionList
or use your 2nd query, which is correct

Access count of related records of an entity Entity Framework

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?

Entity framework relationships

I have these three entities:
public class Dog
{
public int DogId { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public bool Checked { get; set; }
public string DogImage { get; set; }
public virtual ICollection<Result> Results { get; set; }
}
public class Event
{
public int EventId { get; set; }
public string EventName { get; set; }
public string EventLocation { get; set; }
public string EventType { get; set; }
public string EventDate { get; set; }
public virtual ICollection<Result> Results { get; set; }
}
public class Result
{
public int ResultId { get; set; }
public int Track { get; set; }
public int Obedience { get; set; }
public int Protection { get; set; }
[ForeignKey("Dog")]
public int DogId { get; set; }
public virtual Dog Dog { get; set; }
[ForeignKey("Event")]
public int EventId { get; set; }
public virtual Event Event { get; set; }
}
I´ve been getting help from here before in order to set it up like this.
Entity Framework errors when trying to create many-to-many relationship
So the way it is now I guess the result is the "glue" that ties these classes together containing foreign keys to the two other tables.
What I have been trying to achieve for days now is to:
Create an event.
Add dogs to the event.
Add results to the dogs participating in the choosenEvent.
Lets say I create an event like this:
[HttpPost]
public ActionResult CreateEvent(Event newEvent)
{
newEvent.EventDate = newEvent.EventDate.ToString();
_ef.AddEvent(newEvent);
return View();
}
Now I guess the next step would be to add a list of dogs to this event and in order to do that I need to somehow use my result-class since that's the "glue"-class. Please let me know if I'm even on the right track here.
It is not really a good idea to do many to many relationships like how you've done. See here
In order to get a proper many to many relationship, mapped in the proper way in the database, that doesn't have pitfalls, I would try it this way:
public class Dog {}
public class Event {}
public class Result {}
// This is a linking table between Dog and Results
public class DogResult
{
public int Id {get;set;}
public int DogId {get;set;}
public int ResultId {get;set;}
}
// This is a linking table between Events and Results
public class EventResult
{
public int Id {get;set;}
public int EventId {get;set;}
public int ResultId {get;set;}
}
When you now write your query you can do this:
using (var context = new DbContext())
{
var dogs = context.Dogs();
var dogResults = context.DogResults();
var results = context.Results();
var dogsAndResults = dogs.Join(
dogResults,
d => d.Id,
r => r.DogId,
(dog, dogResult) => new { dog, dogResult })
.Join(
results,
a => a.dogResult.ResultId,
r => r.Id,
(anon, result) => new { anon.dog, result });
}
It is a bit nasty looking, but it will give you back a list of anonymous objects containing a Dog and its related Result. But obviously it would be better to do this in a stored proc:
using (var context = new DbContext())
{
var results = context.Database.ExecuteStoreQuery<SomeResultDto>("SELECT * .... JOIN ... ");
}
This is cleaner, because you are using SQL.
This is a more complex way of dealing with it. But far more performant, especially if you understand fully how entity framework executes LINQ.
Obviously if you want to create these links:
using (var context = new DbContext())
{
context.Dogs.AddRange(dogs); // dogs being a list of dog entities
context.Results.AddRange(results); // events being a list of results entities
context.DogResults.AddRange(dogResults); // a list of the links
}
It is completely up to you how you create these links. To turn this into a sproc as well, you want to create some custom User Defined Table Types and use them as a Table Value Parameter.
var dogResults = dogs.SelectMany( d => results.Select ( r => new DogResult { DogId = d.Id, ResultId = r.Id } ) );
That is a beast of a LINQ query and basically it gets every dog and links it to every result. Run it in LinqPad and Dump the values.
I've only done this using the fluent method (when I was learning I found you can do everything in fluent, but not with annotations, so I've not looked into them), the following creates a many to many between my Unit entity and my UnitService entity:
modelBuilder.Entity<Unit>()
.HasMany<UnitService>(u => u.Services)
.WithMany(us => us.Units);
This code is in the protected override void OnModelCreating(DbModelBuilder modelBuilder) method.
In your case Event is Unit and Dog is UnitService.
Oh ooops, you don't need that at all, your 'join' table is your results table, in my case I don't care about the join table so its all hidden.
Maybe something like:
modelBuilder.Entity<Result>()
.HasMany<Event>(e => e.Results);
modelBuilder.Entity<Result>()
.HasMany<Dog>(d => d.Results);

Assign aggregate result to the entity property not pulling all subquery rows

I have a Comment and Votes related to the comment.
[Table("QAComment")]
public class QaComment : IEntity
{
[Key, Column("QACommentID")]
public int Id { get; set; }
// ...
public virtual ICollection<QaCommentVote> Votes { get; set; }
[NotMapped]
public int OverallVote { get; set; }
}
[Table("QACommentVote")]
public class QaCommentVote : IEntity
{
[Key, Column("QACommentVoteID")]
public int Id { get; set; }
[ForeignKey("QAComment")]
public int QaCommentId { get; set; }
public int Value { get; set; }
public virtual QaComment QaComment { get; set; }
}
I need to get comments with the sum of their votes, not pulling all votes to the application.
The ways I can see to achive this:
1. Make a database view for Commment and calc votes sum in there.
Cons: dont wanna make extra-views
2. Via LINQ:
var comments =
Set<QaComment>()
.Select(c => new QaComment() {/* assign every property once again and calc OverallVote */});
Cons: don't like to assign allproperties once again.
Is there a better way devoid of that cons?
UPDATE
This is what I want as a result of LINQ:
SELECT
qac.*,
(SELECT SUM(v.Value)
FROM QACommentVote v
WHERE v.QACommentID = qac.QACommentID) as OverallVote
FROM QAComment qac
You can fetch QaComment and the sum you're looking for separately as anonymous type and merge them into one object using LINQ to Objects:
var comments
= Set<QaComment>()
.Select(c => new { c, sum = c.Votes.Sum(v => v.Value))
.AsEnumerable() // to make next query execute as LINQ to Objects query
.Select(x => { x.c.OverallVote = x.sum; return x.c; })
.ToList();
But to make point clear: I haven't tested that :)

How to query a child object

public class Employee
{
public int Id { get; set; }
public string Title { get; set;}
//....other fields....
//......
//public Topics Interest { get; set; }
public IList<Topics> Interests { get; set; }
}
public class Topics
{
public int Id { get; set; } ;
public string Name { get; set; } ;
//other fields
}
public static IQueryable<EmployeeObject> QueryableSQL()
{
IQueryable<EmployeeObject> queryable = EmployeeRepository.GetAllEmployee();
}
My above data structure has Employee and within it has multiple interests and each interest has multiple topics
My Question is:
How would i search Employee.Interests.Name ?
//i need help construct the linq....
//the below will not work and look for something in the `EmployeeObject` rather in `Interests`
IList<EmployeeObject> _emps = QueryableSQL().Where(x => x.Name== "Chess").ToList();
It depends on what you want. Do you want items where any of their interests match a given value?
var query = QueryableSQL().Where(employee =>
employee.Interests.Any(interest => interest.Name == "Chess"));
When you've been able to explain in English the query that you want the translation to LINQ will be a lot easier.
You can use Any on the child collection to find matching EmployeeObjects
IList<EmployeeObject> _emps =
QueryableSQL().Where(x => x.Interests
.Any(i => i.Name== "Chess"))
.ToList();

Categories

Resources