trying to get the concert name, date and venue (which is stored on another table)
but it doesn't seem to be working, but it keeps pulling back null.
var test = from f in db.Concert
where f.Name.StartsWith(concertName)
select new
{
f.Name,
f.StartDateTime,
venues = from v in db.Venues
where v.ID == f.VenueID
select v.Address
}
Edit:
The relationship between Venue and Concert is that Concert has a VenueID that relates to the Venue ID. I need to pass a string back. something like
foreach (var e in test)
{
html += "<div> e.Name +":" + e.Address </div>;
}
You can use group join to get all Venues related to Concert
var test = from f in db.Concert
join v in db.Venues on f.VenueID equals v.ID into g
where f.Name.StartsWith(concertName)
select new
{
f.Name,
f.StartDateTime,
Venues = g.Select(x => x.Address)
};
Usage of results:
foreach (var e in test)
{
// e.Name
// e.StartDateTime
foreach(var address in e.Venues)
// address
}
It looks like it's safe to assume a 1:1 relationship between Concerts and Venues. Given that, you can use join instead.
var test = from f in db.Concert
join v in db.Venues on v.ID equals f.VenueID
where f.Name.StartsWith(concertName)
select new
{
f.Name,
f.StartDateTime,
v.Address
};
If you have a foreign key relationship set up, You don't need to manually query for venues. In that case you get the venues using f.Venue.
Related
There seem to be lots of questions about SQL to LINQ, but I can't seem to find examples with joined tables and grouping; specifically with a need to get data from multiple tables.
Take this simple SQL:
SELECT
s.showId, s.showName, v.venueName, Min(dateTime) startDate
FROM
shows s
INNER JOIN venues v ON s.venueId = v.venueId
INNER JOIN showDates d ON s.showId = d.showId
GROUP BY
s.showId
The best I can come up with is the following
var ungrouped = (
from s in db.Shows
join v in db.Venues on s.VenueId equals v.VenueId
join d in db.ShowDates on s.ShowId equals d.ShowId
select new { s, v, d }
).ToList();
var grouped = (
from s in ungrouped
group s by s.s.ShowId into grp
select new
{
showId = grp.Key,
name = (from g in grp select g.s.showName).FirstOrDefault(),
venue = (from g in grp select g.v.VenueName).FirstOrDefault(),
startDate = grp.Max(g => g.d.DateTime)
}
);
This works but it feels messy. I don't like:
It being split into two statements
Having to repeatedly write (from g in grp select ...).FirstOrDefault()
Bits like s.s.ShowId
How its vastly more lines of code than the SQL
This example is a simple one, it only gets worse when I have 5+ tables to join and 10+ columns to select.
Question: Is this the best way to do this, and I should just accept it; or is there a better way to write this query?
I am not sure if you are looking for something like this but it's a bit cleaner, it's not split in 2 statements and you might find it helpful. I couldn't use a dbcontext so I used lists to make sure the syntax is correct.
var res = Shows.Join(Venues,
show => show.VenueID,
venue => venue.VenueID,
(show, venue) => new { show, venue })
.Join(ShowDates,
val => val.show.ShowID,
showdate => showdate.ShowID,
(val, showDate) => new { val.show, val.venue, showDates = showDate })
.GroupBy(u => u.show.ShowID)
.Select(grp => new
{
showId = grp.Key,
name = grp.FirstOrDefault()?.show.showName,
venue = grp.FirstOrDefault()?.venue.VenueName,
startDate = grp.Max(g => g.showDates.DateTime)
});
we need to now realation beetwen them one to one or one to many , but not too far from this answer.
var GrouppedResult = Shows.Include(x=>x.Veneu).Include(x=>x.ShowDates)
.Where(x=>x.Veneu.Any()&&x.ShowDates.Any())
.GroupBy(x=>x.ShowId)
.Select(x=>///anything you want);
or
from show in Shows
join veneu in Veneu on veneu.VeneuId equals show.VeneuId
join showDates in ShowDates on showDates.ShowId=show.ShowID
group show by show.Id into grouppedShows
select new { ///what you want };
I'm trying to do something very simple.
I have two tables in my database that I would like to query using linq.
Table of Books, and table of GenreTypes. The result of this query would go to my web Api.
Here is a code snippet:
public List<BooksChart> GetBooksChart()
{
var results = from b in _dbcontext.Books
join g in _dbcontext.GenreTypes
on b.GenreTypeId equals g.Id
group g by g.Name into n
select (z => new BooksChart
{
category_name = n.Key,
value = n.Count()
}).ToList();
return results;
}
public class BooksChart
{
public string category_name;
public int value;
}
The results of the grouping "n" I would like to store them in BooksChart class to construct the Api.
This code is not compiling.
Previously, I was querying only one table of Books which I have divided into Books and GenreTypes.
My previous working code for querying Books was :
var results = _dbcontext
.Books
.GroupBy(x => x.GenreType)
.Select(z => new BooksPieChart
{
category_name = z.Key,
value = z.Count()
}).ToList();
return results;
EDIT
What I want to achieve in SQL is the following:
select count(*), g.Name
from books b, GenreTypes g
where b.GenreTypeId = g.Id
group by g.Name;
You are mixing the two syntax options of query and method. For query syntax you need to do the projection (select) like this:
return (from b in _dbcontext.Books
join g in _dbcontext.GenreTypes on b.GenreTypeId equals g.Id
group g by g.Name into n
select new BooksChart {
category_name = n.Key,
value = n.Count()
}).ToList();
The format of (z =>....) is the declaration of the labmda passed to the Select method.
Site notes:
As #Rabbi commented, since you are using EF, consider properly defining navigation properties. It will make querying simpler.
Side note for the sql - consider using joins instead of multiple tables in the from: INNER JOIN ON vs WHERE clause
The parentheses must surround the whole query, like so:
var results = (from b in _dbcontext.Books
join g in _dbcontext.GenreTypes
on b.GenreTypeId equals g.Id
group g by g.Name into n
select new BooksChart
{
category_name = n.Key,
value = n.Count()
}).ToList();
The compilation error is due to this (z => which is not needed at all.
I have this simple code that returns a list of products but now I need to somehow fetch the same lis of products BUT i need to add a new column or value based on a view count.
var products = db.Products.Where(p => p.ProductOwnerUserId == userID).OrderByDescending(p => p.ProductID);
this is what i have so far but i am no expert in LINQ so i was wondering if someone could help me here.
This is a kind of pseudo-code of what i am looking for
var products = from p in db.Products
join pr in db.Reviews on p.ProductID equals pr.ReviewForProductID
into g select new
{
p.*,
ProductView = g.Count(a => a.ReviewForProductID)
};
i have found my OWN answer since nothing came up from you guys... but thanx for the initial tips... im quite new with linq and complexe queries can be hard to understand and fit inside existing code/view
here is my solution:
Thank you for your first answer and well just too bad for the second one that NEVER came... FYI, since my product class is a partial class already a just added another new ProductView.cs partial class containg the new Property and my query (functionnal and tested) looks like this now:
var products = (from p in db.Products
join pr in db.Reviews on p.ProductID equals pr.ReviewForProductID
into g
select new GenericEcomDataAccess.Product
{
ProductID = p.ProductID,
ProductOwnerUserId = p.ProductOwnerUserId,
ProductCurrency = p.ProductCurrency,
ProductDescription = p.ProductDescription,
ProductPrice = p.ProductPrice,
ProductImage = p.ProductImage,
ProductName = p.ProductName,
ProductCount = g.Count()
}).Where(p => p.ProductOwnerUserId == userID)
.OrderByDescending(p => p.ProductID).AsEnumerable();
var products = db.Products.Where(p => p.ProductOwnerUserId == userID)
.OrderByDescending(p => p.ProductID)
.Select(p=> new {Product = p, Count = p.Reviews.Count()});
If you have the foreign keys set up properly
I am trying to query a collection that contains Employee information. When I query that collection I would like to return an enumeration of objects where each object has two fields:
Name
ManagerName
(Note that every Manager is also an Employee!)
Now, here's the problem I am having. When I do a select within a select, the value of the ManagerName field that is returned on each object is:
System.Data.Common.Internal.Materialization.CompensatingCollection<string>
Here's the query:
var query =
from e in db.Employees
select new
{
Name = e.Name,
ManagerName =
from em2 in db.Employees
where (em2.EmployeeID == e.ManagerID)
select em2.Name
};
Specifically, when I look at the value of ManagerName, I see that it is an enumeration that yields a single item. And that the single item is a string that contains the name of the Manager. So, I think I'm close.
Question: How can I change my query so that instead it returns an enumeration of objects where each object simply has two string fields, Name and ManagerName?
Try this:
var query = from e in db.Employees
select new
{
Name = e.Name,
ManagerName = db.Employees
.Where(x => x.EmployeeID == e.ManagerID)
.Select(x => x.Name).SingleOrDefault()
};
However, if you correctly mapped your database with EF (which I suppose you are using), you should have a navigation property you can utilize:
var query = from e in db.Employees
select new
{
Name = e.Name,
ManagerName = e.Manager.Name
};
Looks like a self-join should work:
var query = from e in db.Employees
join m in db.Employees on e.ManagerID equals m.EmployeeID
select new
{
Name = e.Name,
ManagerName = m.Name
};
I am trying to perform a Join between multiple tables in LINQ. I have the following classes:
Product {Id, ProdName, ProdQty}
Category {Id, CatName}
ProductCategory{ProdId, CatId} //association table
And I use the following code (where product, category and productcategory are instances of the above classes):
var query = product.Join(productcategory, p => p.Id, pc => pc.ProdID, (p, pc) => new {product = p, productcategory = pc})
.Join(category, ppc => ppc.productcategory.CatId, c => c.Id, (ppc, c) => new { productproductcategory = ppc, category = c});
With this code I obtain an object from the following class:
QueryClass { productproductcategory, category}
Where producproductcategory is of type:
ProductProductCategoryClass {product, productcategory}
I do not understand where the joined "table" is, I was expecting a single class that contains all the properties from the involved classes.
My aim is to populate another object with some properties resulting from the query:
CategorizedProducts catProducts = query.Select(m => new { m.ProdId = ???, m.CatId = ???, //other assignments });
how can I achieve this goal?
For joins, I strongly prefer query-syntax for all the details that are happily hidden (not the least of which are the transparent identifiers involved with the intermediate projections along the way that are apparent in the dot-syntax equivalent). However, you asked regarding Lambdas which I think you have everything you need - you just need to put it all together.
var categorizedProducts = product
.Join(productcategory, p => p.Id, pc => pc.ProdId, (p, pc) => new { p, pc })
.Join(category, ppc => ppc.pc.CatId, c => c.Id, (ppc, c) => new { ppc, c })
.Select(m => new {
ProdId = m.ppc.p.Id, // or m.ppc.pc.ProdId
CatId = m.c.CatId
// other assignments
});
If you need to, you can save the join into a local variable and reuse it later, however lacking other details to the contrary, I see no reason to introduce the local variable.
Also, you could throw the Select into the last lambda of the second Join (again, provided there are no other operations that depend on the join results) which would give:
var categorizedProducts = product
.Join(productcategory, p => p.Id, pc => pc.ProdId, (p, pc) => new { p, pc })
.Join(category, ppc => ppc.pc.CatId, c => c.Id, (ppc, c) => new {
ProdId = ppc.p.Id, // or ppc.pc.ProdId
CatId = c.CatId
// other assignments
});
...and making a last attempt to sell you on query syntax, this would look like this:
var categorizedProducts =
from p in product
join pc in productcategory on p.Id equals pc.ProdId
join c in category on pc.CatId equals c.Id
select new {
ProdId = p.Id, // or pc.ProdId
CatId = c.CatId
// other assignments
};
Your hands may be tied on whether query-syntax is available. I know some shops have such mandates - often based on the notion that query-syntax is somewhat more limited than dot-syntax. There are other reasons, like "why should I learn a second syntax if I can do everything and more in dot-syntax?" As this last part shows - there are details that query-syntax hides that can make it well worth embracing with the improvement to readability it brings: all those intermediate projections and identifiers you have to cook-up are happily not front-and-center-stage in the query-syntax version - they are background fluff. Off my soap-box now - anyhow, thanks for the question. :)
What you've seen is what you get - and it's exactly what you asked for, here:
(ppc, c) => new { productproductcategory = ppc, category = c}
That's a lambda expression returning an anonymous type with those two properties.
In your CategorizedProducts, you just need to go via those properties:
CategorizedProducts catProducts = query.Select(
m => new {
ProdId = m.productproductcategory.product.Id,
CatId = m.category.CatId,
// other assignments
});
take look at this sample code from my project
public static IList<Letter> GetDepartmentLettersLinq(int departmentId)
{
IEnumerable<Letter> allDepartmentLetters =
from allLetter in LetterService.GetAllLetters()
join allUser in UserService.GetAllUsers() on allLetter.EmployeeID equals allUser.ID into usersGroup
from user in usersGroup.DefaultIfEmpty()// here is the tricky part
join allDepartment in DepartmentService.GetAllDepartments() on user.DepartmentID equals allDepartment.ID
where allDepartment.ID == departmentId
select allLetter;
return allDepartmentLetters.ToArray();
}
in this code I joined 3 tables and I spited join condition from where clause
note: the Services classes are just warped(encapsulate) the database operations
public ActionResult Index()
{
List<CustomerOrder_Result> obj = new List<CustomerOrder_Result>();
var orderlist = (from a in db.OrderMasters
join b in db.Customers on a.CustomerId equals b.Id
join c in db.CustomerAddresses on b.Id equals c.CustomerId
where a.Status == "Pending"
select new
{
Customername = b.Customername,
Phone = b.Phone,
OrderId = a.OrderId,
OrderDate = a.OrderDate,
NoOfItems = a.NoOfItems,
Order_amt = a.Order_amt,
dis_amt = a.Dis_amt,
net_amt = a.Net_amt,
status=a.Status,
address = c.address,
City = c.City,
State = c.State,
Pin = c.Pin
}) ;
foreach (var item in orderlist)
{
CustomerOrder_Result clr = new CustomerOrder_Result();
clr.Customername=item.Customername;
clr.Phone = item.Phone;
clr.OrderId = item.OrderId;
clr.OrderDate = item.OrderDate;
clr.NoOfItems = item.NoOfItems;
clr.Order_amt = item.Order_amt;
clr.net_amt = item.net_amt;
clr.address = item.address;
clr.City = item.City;
clr.State = item.State;
clr.Pin = item.Pin;
clr.status = item.status;
obj.Add(clr);
}
var query = from a in d.tbl_Usuarios
from b in d.tblComidaPreferidas
from c in d.tblLugarNacimientoes
select new
{
_nombre = a.Nombre,
_comida = b.ComidaPreferida,
_lNacimiento = c.Ciudad
};
foreach (var i in query)
{
Console.WriteLine($"{i._nombre } le gusta {i._comida} y naciĆ³ en {i._lNacimiento}");
}
it has been a while but my answer may help someone:
if you already defined the relation properly you can use this:
var res = query.Products.Select(m => new
{
productID = product.Id,
categoryID = m.ProductCategory.Select(s => s.Category.ID).ToList(),
}).ToList();