Linq to Entities Distinct on Column without Anonymous Type - entity-framework

I am using Entity Framework 5.0 and I wish to return a list of objects, however, I want to perform a DISTINCT on one of the properties on each object within the list.
I know there are a few questions similar to mine already on Stackoverflow, however, I am still struggling with this one.
Currently my query looks like this
public IList<tblcours> GetAllCoursesByOrgID(int id)
{
return _UoW.tblcoursRepo.All.Where(c => c.tblCourseCategoryLinks.Any(cl => cl.tblUnitCategory.tblUnit.ParentID == id))
.OrderBy(c => c.CourseTitle)
.ToList();
}
However, I need to perform a DISTINCT on the property MainHeadingID to remove any objects already with the same ID, but still returning the entire object with all its properties.
Preferably, I would like to return IList, as you can see from my method, and not an Anonymous Type.
Any help with this is greatly appreciated.
Thanks.

Have you tried using GroupBy?
_UoW.tblcoursRepo.All.GroupBy(c => c.MainHeadingId)
.Select(g => g.FirstOrDefault())

Related

How to Optionally include .Includes()... a .IncludeIf(...) if you will? [duplicate]

This question already has answers here:
EF Core linq and conditional include and theninclude problem
(2 answers)
Closed 1 year ago.
I am creation a repo class to for my EF entities. I have a primary entity, lets call it Person. Person of course has collections Addresses, Cars, Pets, Loved Ones, and Secrets
When I use repo.GetPerson(id) I would like to include some sort of flag to indicate if the query should .Include() any of the collections.Something like [Flags] public enum AlsoInclude {Nothing=0, Addresses=1,Cars=2,Pets=4,LovedOnes=8,Secrets=16}; So GetPerson becomes Person GetPerson(Guid id, AlsoInclude alsoInclude)
Normally I would use people.Include(p=>p.Addresses).Include(p=>p.Cars)/*...*/;
I believe if I want to conditionally include the various collections, I would have to write 2^5 if tests for all the combinations.
Does something like IncludeIf(...) exists? Something where I could express
Person GetPerson(Guid id, AlsoInclude alsoInclude
=> people.IncludeIf(alsoInclude.HasFlag(AlsoInclude.Addresses),p=>p.Addresses)
.IncludeIf(alsoInclude.HasFlag(AlsoInclude.Cars),p=>p.Cars) /*...*/
.Single(p=>p.Key==id);
Thanks in Advance.
-Df5
You can very easily do optional includes by composing the query conditionally, somewhat like this:
Person GetPerson(Guid id, AlsoInclude alsoInclude)
{
var query = people;
if (alsoInclude.HasFlag(AlsoInclude.Addresses))
query = query.Include(p => p.Addresses);
if (alsoInclude.HasFlag(AlsoInclude.Cars))
query = query.Include(p => p.Cars)
/*Any other conditional clauses go here*/
return query.Single(p => p.Key == id);
}
You can then create an extension method that does this automatically to achieve exactly your theoretical IncludeIf operator.

Does Npgsql support projection queries?

If I do this...
Context.Orders.Select(o => o.User.UserId);
... I get an exception because User is null. I can use Include instead,
Context.Orders.Include(o => o.User).Select(o => o.User.UserId);
... but shouldn't User be loaded automatically?
EDIT:
The first snippet of code doesn't work when the Select is applied to the result of a function. Which type should the function return in order to tack the Select onto the database query?
I've tried IEnumerable<Order> and IQueryable<Order>.

CS0266 Cannot implicitly convert type 'System.Collections.Generic.List<System.Linq.IGrouping to 'System.Collections.Generic.List'

I am using Entity Framework 7 Code First
I have a function that needs to returns a list of Countries(ids,Names) linked to a User.
The User isn't directly linked to the Country but is linked via the City. City is linked to State. State is linked to Country.
I decided to use a GroupBy to get the list of countries.
public async Task<IEnumerable<Country>> Search(int userId)
{
var table = await _db.Cities
.Include(ci => ci.States.Country)
.Select(ci => ci.States.Country)
.OrderBy(co => co.CountryName)
.GroupBy(co=>co.pk_CountryId)
.ToListAsync()
;
return table;
}
However I get the error:
CS0266 Cannot implicitly convert type
'System.Collections.Generic.List <System.Linq.IGrouping> to
'System.Collections.Generic.List'
How do I return a variable IEnumerable<Country> as that is what the receiving code expects i.e. a list of Countries?
Am I doing my grouping correct?
For performance I assume grouping is better than a distinct or a contains
If you want to have the distinct countries, you can use a select afterwards to select the first country in each IGrouping<int,Country>:
public async Task<IEnumerable<Country>> Search(int userId)
{
return await _db.Cities
.Include(ci => ci.States.Country)
.Select(ci => ci.States.Country)
.OrderBy(co => co.CountryName)
.GroupBy(co=>co.pk_CountryId)
.Select(co => co.FirstOrDefault())
.ToListAsync();
}
Also a little sidenote, the Include isn't necessary here, eager loading the countries would only be useful if you were to return the States and wanted its Country property be populated. The Select makes sure you're grabbing the Country, you're not even fetching the states anymore from database.

bottleneck using entity framework inheritance

so first my entities
the problem i want to have a page with all the story titles and their types
there are three stories LongStory , CoOpStory, GenericStory
the generic story is associated with StoryType for the type of the generic story
i have two problems
first when i want to check if the story is LongStory or CoOpStory i have to get all the entity and check the entity type if it is LongStory then do something , i don't know how to retrieve some data [only the title] and check the type
my second problem like i said i want to have a page with all the story titles and their types i don't know how to do that without making a lot of queries , i can't make a join to the StoryType table because it must be GenericStory to be associated with that , so what i do first get all the stories then do an extra query for every GenericStory to get the type
You are looking of OfType and Concat extension methods.
To get only LongStory instances you just need to call:
var longStories = context.Stories.OfType<LongStory>().ToList();
To get your bigger query it is little bit more complex. You can either try:
var allStories = context.Stories
.OfType<GenericStory>()
.Include("StoryType") // I'm not sure how this works with concat
.Concat(
context.Stories.OfType<LongStory>.Concat(
context.Stories.OfType<CoOpStory>()));
Or you can do a projection:
var allStories = context.Stories
.OfType<GenericStory>()
.Select(s => new { s.Title, s.StoryType.Name })
.Concat(
context.Stories
.OfType<LongStory>
.Select(s => new { s.Title, "LongStory" })
.Concat(
context.Stories
.OfType<CoOpStory>()
.Select(s => new { s.Title, Type })));
Ladislav's answer is for your second question. Here is a possible solution to your first question.
As far as I can see you cannot query directly the type in an projection (using GetType() for instance won't work in LINQ to Entities). But the following will work if you want for instance only query the title and the type of a story:
var stories = context.Stories
.Select(s => new
{
Title = s.Title,
Type = (s is LongStory) ? "LongStory" :
(s is CoOpStory) ? "CoOpStory" :
(s is GenericStory) ? "GenericStory" :
(s is Story) ? "Story" : // forget this if Story is abstract
"Unknown"
}).ToList();
You would get a list of anonymous objects where the Type property represents the type as your custom string in this query.
Not very nice because you had to change this query every time you add a new class to the hierarchy. Also the order matters (most derived classes must be first in the expression for the Type property). But I don't know another way.
Have you tried something like this?
context.Stories.OfType<LongStory>.Where(...).Cast<Story>()
.Union(context.Stories.OfType<GenericStory>.‌​Where(...).Include(s => s.StoryType).Cast<Story>())
.Union(context.Stories.OfType<CoOpStory>.Where(...).Cast<Story>());

one to many join - taking only the last one on the many part

I'm quite a newbie in EF, so I'm sorry if my question has been answered before.. I just can't figure out the syntax..
I have two entities, Category & Product, where one category has many products.
I want to get all categories, with only their latest product (it has a date property named timestamp)
I have no idea how to do that. :-/
If possible I'd like to know the syntax of the two ways to write it, both the sql-like syntax, and the C# like syntax, e.g.:
ctx.Categories.Include("Products").ToList()
from c in ctx.Categories.Include("Products")
Thanks!
Here's the SQL-like way:
var categories =
from p in products
group p by p.Category into g
select new { Category = g.TheKey, LatestProduct = g.Max(p => p.TimeStamp) };
This is the Lambda-way (warning, untested):
var categories = products.GroupBy(p => p.Category)
.Select(g => new { Category = g.TheKey,
LatestProduct = g.Max(p => p.TimeStamp)});
A note on Categories.Include("Products"), you don't need this in your example. You use "Include" for eager-loading, so that for example if you had a list of Categories returned from EF, when you do Categories.Product you will get the associated product.
But all you require is a list of categories, and a single product for each one - which is already returned in the above LINQ query, so no need for Include.