Linq, unable to list only distinct results - c#

I have three tables, car_type, car_manufacturer and car_model. When the user click on the particular vehicle type they want to browse, I'd like to show them a list of available manufacturers. The problem is the list of manufacturers is not distinct or unique. So if my db has three models from Mazda, Mazda will show up on the list 3 times. This is my controller:
public ActionResult Browse(string click_string)
{
var x = carDB.Models
.Include(b => b.Manufacturer)
.Include(a => a.VehicleType)
.Where(a => a.VehicleType.TypeName == click_string);
return View(x.ToList());
}
How can I write this to remove redundant listings? This is all new to me, so go easy on me.

You have to query for Manufacturers, not for Vehicles:
var x = carDB.Models.Where(a => a.VehicleType.TypeName == click_string)
.Select(a => a.Manufacturer)
.Distinct();

It usually works well to try and avoid Distinct altogether. You want manufacturers? Get manufacturers. And determine from there which ones you need: the ones that produce models that have click_string in their type name:
carDB.Manufacturers.Where(manufacturer => manufacturer.Models
.Any(model => model.VehicleType.TypeName == click_string))
You may want to include Models and/or VehicleType, that depends on what you want to show in the view.

First try doing a .Distinct() at the end of the query, if it does not work you might need to provide a custom comparer for the .Distinct()

You should be able to use .Distinct to return the distinct elements.
var x = carDB.Models
.Include(b => b.Manufacturer)
.Include(a => a.VehicleType)
.Where(a => a.VehicleType.TypeName == click_string)
.Distinct();

add distinct
var x = carDB.Models
.Include(b => b.Manufacturer)
.Include(a => a.VehicleType)
.Where(a => a.VehicleType.TypeName == click_string)
.Select(y => y)
.Distinct();
The .Select() might be a bit verbose but without trying it in my visual studio i put it in there for saftey

Related

Cannot implicitly convert type 'System.Collections.Generic.List<System.Collections.Generic.IEnumerable<xxx>>' to 'System.Collections.Generic.List<xxx>

I am getting the following error. I googled it for more than a day but I cant find the exact solution, Please help me Thank you
ERROR: Cannot implicitly convert type
System.Collections.Generic.List<System.Collections.Generic.IEnumerable<ADCO.eJMC.EntityDataModel.ShareholderUser>>
to
System.Collections.Generic.List<ADCO.eJMC.EntityDataModel.ShareholderUser>
I used the following code
List<ShareholderUser> list = new List<ShareholderUser>();
list = dataContext.EJMCShareholderApprovals
.Include(s => s.Shareholder.ShareholderUsers)
.Where(e => e.EJMCRequestId == requestId)
.Select(s => s.Shareholder.ShareholderUsers
.Where(x => x.AccessMode == true))
.ToList();
The problem is that at the moment, you're selecting a sequence of sequences - one sequence of ShareholderUser items for each Shareholder. If you just want a list of ShareholderUser items, you need to flatten the results. That's most easily done using SelectMany, which can actually replace your Select call in this case.
List<ShareholderUser> list = dataContext.EJMCShareholderApprovals
.Where(e => e.EJMCRequestId == requestId)
.SelectMany(s => s.Shareholder.ShareholderUsers)
.Where(x => x.AccessMode == true)
.ToList();
Note how breaking the query over multiple lines makes it much simpler to read, too. Also, there's no point in initializing the list variable to a new List<ShareholderUser> if you're then immediately going to give it a different value. I've also removed the Include call, as that was unnecessary - you're explicitly selecting Shareholder.ShareholderUsers in the query, so you don't need to include it.
This should do it?
var list = dataContext.EJMCShareholderApprovals
.Include(s => s.Shareholder.ShareholderUsers)
.Where(e => e.EJMCRequestId == requestId)
.Select(s => s.Shareholder.ShareholderUsers
.Where(x => x.AccessMode == true)).ToList();
though you are doing select on to ShareHolderUsers? Are you trying to get a list of ShareHolderUsers or a list of lists of ShareHolderUsers?
.Select(s => s.Shareholder.ShareholderUsers

Linq - where inside include

I know that this won't work as written, but I'm struggling to see the right answer, and this non-functional code hopefully illustrates what I'm trying to achieve:
var defaults = _cilQueryContext.DefaultCharges
.Where(dc => dc.ChargingSchedule_RowId == cs.RowId);
List<DevelopmentType> devTypes =
defaults.Select(dc => dc.DevelopmentType)
.Include(d => d.DefaultCharges)
.Include(d => d.OverrideCharges.Where(oc => oc.ChargingSchedule_RowId == cs.RowId))
.Include(d => d.OverrideCharges.Select(o => o.Zone))
.ToList();
Essentially, I had presumed this required a join, but seeing as I'm trying to select a parent object containing two related types of children, I can't see what would go in the join's "select new" clause.
As far as I am aware Include does not support this type of sub-querying. Your best option is to use projection e.g.
List<DevelopmentType> devTypes =
defaults.Include(x => x.DefaultCharges)
.Include(x => x.OverrideCharges)
.Select(x => new {
DevType = x.DevelopmentType,
Zones = x.OverrideCharges.Where(oc => oc.ChargingSchedule_RowId == cs.RowId)
.Select(oc => oc.Zone).ToList()
})
.Select(x => x.DevType)
.ToList();

C# EF Deep Lambda Distinct Count Query

This is the query I am trying to do.
var commentActivity = project.ProjectDoc
.Select(c => c.Comment.Select(i => i.UserID))
.Distinct()
.Count();
What I want is the number of comments from distinct users on a specific project, but ANY ProjectDoc. This query "works" the result is just wrong. The model is like this, generically sketched.
Project
ProjectDoc
Comment
Update: I had to go one level deeper, based on the answer below I tried a few things that didn't work so I though I would post this as a reference. Note the two SelectMany methods.
var replyActivity = project.ProjectDoc
.SelectMany(c => c.Comment.SelectMany(r => r.CommentReply.Select(u => u.UserID)))
.Distinct()
.Count();
Use SelectMany instead of Select
project.ProjectDoc
.SelectMany(c => c.Comment.Select(i => i.UserID))
.Distinct()
.Count()
var data = (from con in project.ProjectDoc
select new
{
CommentCount=project.Comment.Count(x=>x.UserID==con.UserID)
}).ToList();
i think this will help you.

Subquery parent id in NHibernate QueryOver

I'm trying to understand how this may work.
What I would have is to have all Trees from a given list of IDs that has not rotten apples.
Looks easy but I'm fresh of NHibernate, not so good in SQL and as you can see I'm stuck.
I wrote this code down here:
Tree treeitem = null;
QueryOver<Apple> qapple = QueryOver.Of<Apple>()
.Where(x => (!x.IsRotten))
.And(Restrictions.IdEq(Projections.Property<Tree>(y => y.Id)))
// Or this one...
//.And(Restrictions.EqProperty(
// Projections.Property<Apple>(y => y.Tree.Id),
// Projections.Property<Tree>(y => y.Id)))
.Select(x => x.Id);
return this.NHibernateSession.QueryOver<Tree>()
.Where(x => x.Id.IsIn(ListOfTreeId))
.WithSubquery.WhereExists<Apple>(qapple)
.SelectList(list => list
.Select(z => z.Id).WithAlias(() => treeitem.Id)
.Select(z => z.Name).WithAlias(() => treeitem.Name)
.Select(z => z.Type).WithAlias(() => critem.Type)
.TransformUsing(Transformers.AliasToBean<Tree>())
.List<T>();
And the pseudo SQL I get is something like this:
SELECT id, name, type FROM trees WHERE id IN (1, 2, 3)
AND EXIST(SELECT id FROM apples WHERE NOT rotten AND apples.idtree = apples.id)
As you can see there's a problem with the subquery that use the same table Id instead of something like that:
EXIST(SELECT id FROM apples WHERE NOT rotten AND apples.idtree = tree.id)
I'm bit lost actually. Maybe there's another way to build this up.
Any help is welcome, thanks.
Im not sure why you are using resulttransformer when the return type is the same as the query type
return NHibernateSession.QueryOver<Tree>()
.Where(t => t.Id.IsIn(ListOfTreeId))
.JoinQueryOver<Apple>(t => t.Apples)
.Where(a => !a.IsRotten)
.List();
Update: the Compiler chooses ICollection<Apple> while it really should choose Apple therefor specify the generic argument in JoinQueryOver explicitly
Update2: to get them unique
opt 1)
...
.SetResultTransformer(Transformers.DistinctRootEntity());
.List();
opt 2)
Tree treeAlias = null;
var nonRottenApples = QueryOver.Of<Apple>()
.Where(a => !a.IsRotten)
.Where(a => a.Tree.Id == treeAlias.Id)
.Select(x => x.Id); <- optional
return NHibernateSession.QueryOver(() => treeAlias)
.Where(t => t.Id.IsIn(ListOfTreeId))
.WithSubquery.WhereExists(nonRottenApples)
.List();

Counting grouped data with Linq to Sql

I have a database of documents in an array, each with an owner and a document type, and I'm trying to get a list of the 5 most common document types for a specific user.
var docTypes = _documentRepository.GetAll()
.Where(x => x.Owner.Id == LoggedInUser.Id)
.GroupBy(x => x.DocumentType.Id);
This returns all the documents belonging to a specific owner and grouped as I need them, I now need a way to extract the ids of the most common document types. I'm not too familiar with Linq to Sql, so any help would be great.
This would order the groups by count descending and then take the top 5 of them, you could adapt to another number or completely take out the Take() if its not needed in your case:
var mostCommon = docTypes.OrderByDescending( x => x.Count()).Take(5);
To just select the top document keys:
var mostCommonDocTypes = docTypes.OrderByDescending( x => x.Count())
.Select( x=> x.Key)
.Take(5);
You can also of course combine this with your original query by appending/chaining it, just separated for clarity in this answer.
Using the Select you can get the value from the Key of the Grouping (the Id) and then a count of each item in the grouping.
var docTypes = _documentRepository.GetAll()
.Where(x => x.Owner.Id == LoggedInUser.Id)
.GroupBy(x => x.DocumentType.Id)
.Select(groupingById=>
new
{
Id = groupingById.Key,
Count = groupingById.Count(),
})
.OrderByDescending(x => x.Count);

Categories