EF Linq Query nested .ToList() - c#

looks like I got stuck with a nested Linq Query. I have 4 Tables which I want to join. Basically a journal has one Recipient and multiple Readers. I'd like to show the Journal with it's Recipient and all it's Readers. Here's the EF Query
var myJournals = (
from s in db.Journals
where !s.Blacklist
join recToJournals in db.RecipientsToJournals on s.JournalID equals recToJournals.JournalID
join recipients in db.Recipients on recToJournals.RecipientID equals recipients.RecipientID
join reaToJournals in db.ReadersToJournals on s.JournalID equals reaToJournals.JournalID
join readers in db.Readers on reaToJournals.ReaderID equals readers.ReaderID
select new AnalysisViewModel
{
JournalID = s.JournalID,
Title = s.Title,
RecipientName = recipients.FullName,
ReaderList = readers.FullName.ToList()
});
return View(myJournals);
Here's the ViewModel:
public class AnalysisViewModel
{
public int JournalID { get; set; }
public string Title { get; set; }
public List<Char> ReaderList { get; set; }
public string ReaderName { get; set; }
public string RecipientName { get; set; }
}
Here I'll get an Exception System.NotSupportedException: The method 'ToList' is not supported when called on an instance of type 'String'.
If I use ReaderName = readers.FullName it works, but I get a List with multiple Journals and their Readers.
How can I show only one Journal with it's Recipient and all it's Readers?

This does not make sense. Why are you calling ToList on a string? Why would you even want List<char>? Change your model so the type is of string and remove ToString
Change 1 - in your linq statement
ReaderList = readers.FullName // remove .ToList
Change 2 - in your model
public string ReaderList { get; set; }
Although it is not technically wrong it is not best practice to name a property of type string (or any non collection type for that mater) with the suffix List. A more suitable name would be ReaderName.

First of all change your ViewModel
public class AnalysisViewModel
{
public int JournalID { get; set; }
public string Title { get; set; }
public string RecipientFullName { get; set; }
public List<string> ReadersFullNames { get; set; }
}
You need GroupBy
var myJournals = from s in db.Journals
where !s.Blacklist
join recToJournals in db.RecipientsToJournals
on s.JournalID equals recToJournals.JournalID
join recipients in db.Recipients
on recToJournals.RecipientID equals recipients.RecipientID
join reaToJournals in db.ReadersToJournals
on s.JournalID equals reaToJournals.JournalID
join readers in db.Readers
on reaToJournals.ReaderID equals readers.ReaderID
select new
{
JournalID = s.JournalID,
Title = s.Title,
RecipientFullName = recipients.FullName,
ReaderFullName = readers.FullName
};
var result = myJournals.GroupBy(j => new { j.JournalID, j.Title, j.RecipientFullName })
.Select(g => new AnalysisViewModel
{
JournalID = g.Key.JournalID,
Title = g.Key.Title,
RecipientFullName = g.Key.RecipientFullName,
ReadersFullNames = g.Select(r => r.ReaderFullName).ToList(),
}
)
.ToList();

Related

Display fields with the same GUIDs together [duplicate]

This question already has answers here:
Check if some items are same in a c# list
(1 answer)
Group by in LINQ
(11 answers)
Closed 4 years ago.
I have a list of type ProductDetailDTO.
List<ProductDetailDTO> productDTOs;
public class ProductDetailDTO
{
public int ProductId { get; set; }
public string Name { get; set; }
public string Category { get; set; }
public byte[] Image { get; set; }
public string Description { get; set; }
public string Brand { get; set; }
public string GUID { get; set; }
public string VariantName { get; set; }
public string VariantValue { get; set; }
public decimal Price { get; set; }
}
I have used linq to bind the data to the list.
var productDetails = (from product in ekartEntities.Products
join productImage in ekartEntities.ProductImages on product.ProductId equals productImage.ProductId
join category in ekartEntities.ProductCategories on product.Category equals category.CategoryId
join mapping in ekartEntities.ProductVariantMappings on product.ProductId equals mapping.ProductId
join variant in ekartEntities.ProductVariants on mapping.ProductVariantId equals variant.ProductVariantId
join inventory in ekartEntities.Inventories on mapping.GUID equals inventory.Guid
where product.ProductId == productDetailDTO.ProductId
select new ProductDetailDTO()
{
ProductId = product.ProductId,
Name = product.Name,
Category = category.Name,
Description = product.Description,
Brand = product.Brand,
Image = productImage.Image,
GUID = mapping.GUID.ToString(),
VariantName = variant.Name,
VariantValue = mapping.Value,
Price = inventory.Price
}).ToList();
Now, I want to display all the variants (VariantName and VariantValue) with the same GUIDs together. How can I achieve that?
You can use GroupBy and Select like this:
var variants = productDTOs
.GroupBy(k => k.GUID)
.Select(v => v
.Select(variant => new
{
variant.VariantName,
variant.VariantValue
}));
You can use Group By
group p by p.GUID into g
select new { Id = g.Key, ProductDetail = g.ToList()).ToList();
If you have tables before group by, then you can add new object in the group itself
group new { p.xyz, n.xyz }
by new { p.GUID } into g
otherwise use let to save the intermediate object in an object and do grouping on it

LINQ Query (Group BY) one column

Consider the following classes
public class DashboardTile
{
public int ID { get; set; }
public int? CategoryID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
public class DashboardTileBO : DashboardTile
{
public bool IsChecked { get; set; }
public List<DashboardTileBO> DashboardTiles { get; set; }
}
I have list of tiles in which some tiles are child of other.Now I want to show my list of tiles in such a way that if it has childs it gets added to the list.
query I am trying
var allDashBoardTiles = (from a in context.DashboardTiles
group a by a.CategoryID into b
select new BusinessObjects.DashboardTileBO
{
ID = a.ID,
Name = a.Name,
Description = b.Description,
DashboardTiles = b.ToList(),
}).ToList();
var list = context.DashboardUserTiles.Where(a => a.UserID == userId).Select(a => a.DashboardTileID).ToList();
allDashBoardTiles.ForEach(a => a.IsChecked = list.Contains(a.ID));
Now in above query when I use group clause and in select if I use a.ID,a.Name etc it says that it doesnot contain definitionor extension method for it.
Table
You can't access the properties of a directly because GroupBy returns IGrouping<TKey,T>. You can include other columns also in your group by and access them like this:-
(from a in context.DashboardTiles
group a by new { a.CategoryID, a.ID, a.Name } into b
select new BusinessObjects.DashboardTileBO
{
ID = b.Key.ID,
Name = b.Key.Name,
DashboardTiles = b.ToList(),
}).ToList();
Edit:
Also, I guess the property DashboardTiles in DashboardTileBO class should be List<DashboardTile> instead of List<DashboardTileBO>, otherwise we cannot fetch it from DashboardTiles data.

Join clause incorrect on multiple join LINQ

I have a multiple join query like this:
public static List<Answer> GetDetailedAnswers(string Tag)
{
using (Database db = new Database())
{
List<Answer> answer =
from quest in db.Question
join answ in db.Answer on quest.ID equals answ.QuestionID
join deal in db.Dealer on answ.DealerID equals deal.ID
join country in db.Country on deal.CountryID equals country.CountryID
where quest.ParentSection == Tag
select new
{
ParentSection = quest.ParentSection,
Section = quest.Section,
Dealer = deal.Name,
OriginalAnswer = answ.Original,
EngAnswer = answ.English,
Region = country.Country
}.ToList();
return answer;
}
}
And i have an internal class like this:
public class Answer
{
public string ParentSection { get; set; }
public string Section { get; set; }
public string Dealer { get; set; }
public string OriginalAnswer { get; set; }
public string EngAnswer { get; set; }
public string Region { get; set; }
}
I get an error on the last join. It says "the type of one of the expressions in the join clause is incorrect. Type inference failed in the call to 'Join'"
What did i miss? Thx
For the error: "AnonymousType#1 does not contain a definition for 'ToList' and no extension method 'ToList'", You can do following.
public static List<Answer> GetDetailedAnswers(string Tag)
{
using (Database db = new Database())
{
List<Answer> answer =
(from quest in db.Question
join answ in db.Answer on quest.ID equals answ.QuestionID
join deal in db.Dealer on answ.DealerID equals deal.ID
join country in db.Country on deal.CountryID equals country.CountryID
where quest.ParentSection == Tag
select new Answer
{
ParentSection = quest.ParentSection,
Section = quest.Section,
Dealer = deal.Name,
OriginalAnswer = answ.Original,
EngAnswer = answ.English,
Region = country.Country
}).ToList();
return answer;
}
}
You need to surround you query within round brackets and then apply .ToList() method to it.
Please check the data type of
deal.CountryID and country.CountryID. this should be same

How do I do a multi-join on two SQL Views in an Entity Framework Model?

I have two views in my model.
I basically need to do an INNER JOIN on them based on three columns:
dataSource
ShowID
EpisodeID
The first thing I don't know how to do is add the SQL "AND" operator to the LINQ expression.
The second thing is, I don't know how to SELECT the JOINED table.
Can someone give me a hand?
var query = (from s in db.TVData_VW_ShowList
from z in db.TVData_VW_Schedule
where s.dataSource = z.dataSource
&& s.ShowID = z.ShowID
&& s.EpisodeId = z.EpisodeId select ...
You can use anonymous types to your advantage here, both to join across multiple columns, and to project into a new type containing data from both sides of the join. Here's a working example using Linq to objects:
namespace LinqExample
{
class Program
{
static void Main()
{
var Shows = new List<ShowData> { new ShowData { dataSource = "foo", EpisodeID = "foo", ShowID = "foo", SomeShowProperty = "showFoo" }};
var Schedules = new List<ScheduleData> { new ScheduleData { dataSource = "foo", EpisodeID = "foo", ShowID = "foo", SomeScheduleProperty = "scheduleFoo" } };
var results =
from show in Shows
join schedule in Schedules
on new { show.dataSource, show.ShowID, show.EpisodeID }
equals new { schedule.dataSource, schedule.ShowID, schedule.EpisodeID }
select new { show.SomeShowProperty, schedule.SomeScheduleProperty };
foreach (var result in results)
{
Console.WriteLine(result.SomeShowProperty + result.SomeScheduleProperty); //prints "showFoo scheduleFoo"
}
Console.ReadKey();
}
}
public class ShowData
{
public string dataSource { get; set; }
public string ShowID { get; set; }
public string EpisodeID { get; set; }
public string SomeShowProperty { get; set; }
}
public class ScheduleData
{
public string dataSource { get; set; }
public string ShowID { get; set; }
public string EpisodeID { get; set; }
public string SomeScheduleProperty { get; set; }
}
}
So to join you can use the join keyword then use on to specify the conditions. && (the logical and operator in C#) will be translated to the SQL AND keyword.
Also, in EF they have what are known as "implicit joins" meaning if I have TableA with a foreign key to TableB, call it fKey.
Doing where TableA.fKey == TableB.pKey will cause the provider to put a join there. To select you simply need to do;
select new { prop1 = TableA.Prop1, prop2 = TableB.Prop1 }
this will create a new anonymous which selects values from both tables.
Below is a more complete example of the join syntax. I think it uses all of the things you asked about;
var result = from a in TableA
join b in TableB on a.fKey equals b.pKey && b.Status equals 1
select new { a.Prop1, a.Prop2, b.Prop1 };
First you need to create an auxiliar class that contains the columns of both views, something like:
public class viewItem
{
public int ShowID { get; set; }
public int EpisodeID { get; set; }
public int dataSource { get; set; }
...
}
then your linq query would be:
var query = (from s in db.TVData_VW_ShowList
join z in db.TVData_VW_Schedule
on s.dataSource equals z.dataSource
where s.ShowID == z.ShowID
&& s.EpisodeID == z.EpisodeID
select new viewItem {
ShowID = s.ShowID,
EpisodeID = s.EpisodeID,
dataSource = s.dataSource,
...
}

Get Linq Subquery into a User Defined Type

I have a linq query, which is further having a subquery, I want to store the result of that query into a user defined type, my query is
var val = (from emp in Employees
join dept in Departments
on emp.EmployeeID equals dept.EmployeeID
select new Hello
{
EmployeeID = emp.EmployeeID
Spaces = (from order in Orders
join space in SpaceTypes
on order.OrderSpaceTypeID equals space.OrderSpaceTypeID
where order.EmployeeID == emp.EmployeeID group new { order, space } by new { order.OrderSpaceTypeID, space.SpaceTypeCode } into g
select new
{
ID = g.Key.SpaceTypeID,
Code = g.Key.SpaceTypeCode,
Count = g.Count()
})
}).ToList();
Definition for my Hello class is
public class Hello
{
public IEnumerable<World> Spaces { get; set; }
public int PassengerTripID { get; set; }
}
Definition for my World class is
public class World
{
public int ID { get; set; }
public string Code { get; set; }
public int Count { get; set; }
}
You are creating anonymous object but you need to specify type name World
select new World
{
ID = g.Key.SpaceTypeID,
Code = g.Key.SpaceTypeCode,
Count = g.Count()
})

Categories