I am trying to join 2 tables while filtering with where clause. The data looks like this:
Category
Name Selected
A 0
B 1
C 0
SubCategory
Name ParentCategory Selected
s1 A 0
s2 B 1
s3 B 0
Expected results:
ParentCatName SubCatName SubCatSelected
B s2 1
B s3 0
Actual results:
ParentCatName SubCatName SubCatSelected
B s2 1
B s3 1 <-- should be 0
The code I am using is this:
IEnumerable<Category> result =
from s in subcategories
join c in categories
on s.Parent equals c.Name into t
from r in t.DefaultIfEmpty()
where r == null ? false : r.Selected == true
select new Category
{
Name = s.Name,
Parent = (r == null ? string.Empty : r.Name),
Selected = r.Selected
};
EDIT: Something that helped me get clarity was to temporarily rewrite this to see the resulting data structures...
var result =
from s in subcategories
join c in categories
on s.Parent equals c.Name into t
from r in t.DefaultIfEmpty()
select new
{
s, r
};
Then I came up with the answer to the filtering of selected categories. See my answer below..
Don't overcomplicate the things. What you are trying to achieve is to filter subcategories by the selected categories. You can get the desired result with the following simple query
var result = from s in subcategories
join c in categories on s.Parent equals c.Name
where c.Selected
select s;
It looks like you're setting it wrong. If r == null then you're setting it to false, otherwise you're setting it to true here: r.Select == true.
Just by reading your query it looks like you may not need that where clause at all.
You probably want something like this:
IEnumerable<Category> result =
from s in subcategories
join c in categories
on s.Parent equals c.Name into t
from r in t.DefaultIfEmpty()
select new Category
{
Name = s.Name,
Parent = (r == null ? string.Empty : r.Name),
Selected = r.Selected
};
Or if you need to do the null check then do this:
IEnumerable<Category> result =
from s in subcategories
join c in categories
on s.Parent equals c.Name into t
from r in t.DefaultIfEmpty()
where r != null //I added the null check here
select new Category
{
Name = s.Name,
Parent = (r.Name), //I removed the null check here
Selected = r.Selected
};
I think, your t value inculudes categoies list. t must be include subcategory list and then you can take selected value of subcategory. So you always get selected value as 1 pls try this:
IEnumerable<SubCategory> result =
from c in categories
join s in subcategories
on c.Name equals s.Parent into t
from r in t.DefaultIfEmpty()
where r == null ? false : r.Selected == true
select new SubCategory
{
Name = s.Name,
Parent = (r == null ? string.Empty : r.Name),
Selected = r.Selected
};
OBS:I'm not try this now. But I think works.
Okay. So I did some more looking and came up with this...
IEnumerable<Category> result =
from s in subcategories
join c in categories.Where(f => f.Selected)
on s.Parent equals c.Name into t
from r in t.DefaultIfEmpty()
where r == null ? false : true
select new Category
{
Name = s.Name,
Parent = s.Name,
Selected = s.Selected,
};
To filter join to only selected parent category, I have added lambda expression right to that data.
Related
I'm trying to make a query ... I'm using entity framework in the project.
The query below is working
public async Task<dynamic> CriarResumo(Pedido pedido)
{
var query = (from p in context.Pedido
join pi in context.PedidoItem on p.Id equals pi.PedidoId
join t in context.Tamanho on pi.TamanhoId equals t.Id
join s in context.Sabor on pi.SaborId equals s.Id
join pia in context.PedidoItemAdicional on pi.Id equals pia.PedidoItemId
join a in context.Adicional on pia.AdicionalId equals a.Id
where p.Id == pedido.Id
select new
{
tamanho = t.Descricao + " - " + t.ML+"ml",
sabor = s.Descricao,
adicionais = a.Descricao,
tempoPreparo = p.TempoTotal,
valorTotal = p.ValorTotal
});
var o = query.FirstOrDefault();
return o;
}
"Adicional" is an associative table (PedidoItemId and AdicionalId) so it is possible that the search returns more than one result.
Ex: PedidoItem Id = 67
The Item has the Adicional->id 1 and the Adicional->id 2.
The way I'm doing I can only get the Adicional in id 1. How can I solve?
You are using .FirstOrDefault() which returns first element of a sequence or a default value if no item is found. If you want to return a collection of items you should use a method that returns it: e.g. .ToList() or .ToArray()
I have a pretty large linq query driving a section of my system, and i am trying to add in a new feature, but the joins seem to be misbehaving.
The old query used to bring back a list of videos which i used to create a view model and only list each video once, with all of the metadata displayed, VisibleStaff, VisiblePlayers and VisibleTeams are all IEnumerable.
Since adding the par tthat drives VisibleStaff, any video with entries in VideosLinkings where the VideoInType flag is set to staff, displays once for each entry, rather than once, and giving me a list of staff members as metadata for VisibleStaff.
I think i am missing a grouping somewhere, but i have tried multiple groups in multiple places and cannot seem to get it right.
Does anyone have any idea where my joins have gone wrong and how i would return a single Video and multiple staff in each VideoModel?
Full Query
from video in Videos
where
video.ClubID == ClubId &&
(VideoFilter.Category == 0 || video.VideoCategoryID == VideoFilter.Category)
join userStaff in Database.Users on video.AddedByUserID.Value equals userStaff.UserID
join videoInTeams in VideoInTeams on video.VideoID equals videoInTeams.VideoID into teamsForVideo
join playerInVideo in Database.PlayersVideos on video.VideoID equals playerInVideo.VideoId into
playersForVideo
join soapVideoLink in Database.VideosLinkings on new {a = video.VideoID, b = VideoInType.SOAPNote}
equals new {a = soapVideoLink.VideoId, b = soapVideoLink.VideoInType} into soapVideoLinks
join staffVideoLink in Database.VideosLinkings on new {a = video.VideoID, b = VideoInType.Staff}
equals new {a = staffVideoLink.VideoId, b = staffVideoLink.VideoInType} into
staffVideoLinks
from svl in staffVideoLinks.DefaultIfEmpty()
join staff in Staff on svl.VideoInKeyId equals staff.StaffID into visibleStaff
let soapLinks = soapVideoLinks.Any(f => f.VideoInKeyId != -1)
let oldExtension =
video.H264Version == "Uploaded"
? ".mp4"
: (video.FlashVersion == "Uploaded" ? ".flv" : video.FileExtension)
where
VideoFilter.ShowSoapVideos || (VideoFilter.ShowSoapVideos == false && soapLinks == false)
orderby video.DateTimeUploaded descending
select new VideoModel
{
Video = video,
Category = video.VideoCategory,
Staff = userStaff.Staff,
ShowDeleteOption = VideoFilter.ShowDeleteOption,
VisibleTeams = teamsForVideo.Select(f => f.Team),
VisiblePlayers = playersForVideo.Select(f => f.Player),
Thumbnail =
video.ThumbnailURL != "" && video.ThumbnailURL != null
? video.ThumbnailURL
: "/Images/Videos/noimage.png",
IsNew = false,
IsMedicalVideo = soapLinks,
VisibleStaff = visibleStaff,
IsStaffVideo = staffVideoLinks.Any()
}
The New Lines
join staffVideoLink in Database.VideosLinkings on new {a = video.VideoID, b = VideoInType.Staff}
equals new {a = staffVideoLink.VideoId, b = staffVideoLink.VideoInType} into
staffVideoLinks
from svl in staffVideoLinks.DefaultIfEmpty()
join staff in Staff on svl.VideoInKeyId equals staff.StaffID into visibleStaff
I'm trying to write a query in a c# program that gets all items out of a database where a particular id in that item is contained in a list I have. I also need to join on a few tables..
What I have is:
var data = from a in db.Apples.Where(a => myApples.contains(a.type))
from b in db.Banans where b.Id = a.bananaPair.Id
from c in db.Coconuts where c.Id = c.coconutPair.Id
select new {
apple = a,
bananaName = b.name,
coconutName = c.name,
});
I get an error on "where b.Id = a.bananaPair.Id" that "cannot implicitly convert int to bool". I think I am mixing types.. the first where is a comparison, and the others is a join condition. How can I do both in the query? I need pieces of information from all 3 tables in my select object.
Thanks
Change it to
var data = from a in db.Apples.Where(a => myApples.contains(a.type))
from b in db.Banans where b.Id == a.bananaPair.Id
from c in db.Coconuts where c.Id == c.coconutPair.Id
select new {
apple = a,
bananaName = b.name,
coconutName = c.name,
});
You had b.Id = a.bananaPair.Id. That assigns a.bananaPair.Id to b.Id. The reason your error was calling this assignment an int is because assignments return the value assigned. You want b.Id == a.bananaPair.Id, which tests whether they're equal.
As commenter #misterManager suggests, you could also use join here. Let me know if this doesn't work, though, it's been so long since I've used query syntax.
var data = from a in db.Apples.Where(a => myApples.contains(a.type))
join b in db.Bananas on a.bananaPair.Id equals b.Id
join c in db.Coconuts on c.coconutPair.Id equals c.Id
select new {
apple = a,
bananaName = b.name,
coconutName = c.name,
});
By the way, I couldn't help but notice your c line: from c in db.Coconuts where c.Id == c.coconutPair.Id, should that be a.coconutPair.Id?
var query = from r in list where r.Id == "" DefaultIfEmpty(String.Empty)
does not work.
How do I have to write a linq query with query style and use the DefaultIfEmpty method?
Assuming your list contains the type Item you would want:
// define your default item
var defaultItem = new Item { ... };
var query = (from r in list where r.Id == "" select r).DefaultIfEmpty(defaultItem);
or in method syntax
var query = list.Where( r => r.Id == "" ).DefaultIfEmpty(defaultItem);
However if you're selecting a specific string property of Item then you may want something like
var query = (from r in list where r.Id == "" select r.StringProperty)
.DefaultIfEmpty(string.Empty);
DefaultIfEmpty is used usually with JOINS, (outer joins).
You may see: How to: Perform Left Outer Joins (C# Programming Guide)
For your case it apears you want to select empty string if the r.Id is null, you can you can do:
var query = from r in list
select new
{
ID = r.Id == null ? string.Empty : r.Id
};
I have a small problem in my where clause in the linq expression below. If I put the number 3 instead of department.Id I get the desired result but when I use department.Id I get nothing in the resultset.
I also want to get a count for the number of filters for that filter name using the query again using distinct.
var dept = Page.RouteData.Values["department"];
var department = (from d in db.Departments
where d.Name.Replace(" ", "-") == dept
select new {d.Id, d.Name}).FirstOrDefault();
var query = from p in db.Products
join f in db.ProductFilters on p.Id equals f.ProductId into filters
from x in filters.Where(x => x.Product.DepartmentId == department.Id
/* if == 3 it works */)
select new { x.Name, x.Id };
Promoted to answer from comments:
Have you checked that the department instance is as you think it should be after the first linq statement - ie has an Id == 3?
Your first query is not finding any valid department and is therefore returning default which most probably means that departmend.Id == 0.