linq query with many-to-many relationship - linq

Let’s assume I have three tables in my database:
Authors(PK Id, AuthorName)
Books(PK Id, BookName)
Authors_Books(FK BookId, FK AuthorId)
I need to write a method which passes in a parameter int[] authorsIds and returns all books (Id, BookName, list of authors of this book) if it was written by any author whose Id contains in int[] authorsIds parameter.
I need LINQ query (query method).
I really need a help. Appreciate your help very much.

var int[] authors = { 1, 2, 3 };
var books = from book in books
where book.Authors.Any(x => authors.Contains(x.AuthorId))
select book;
PS: I assume book.Authors is your reference to Authors_Books table (or maybe has a different name).

this answer is based on the exact structure without considering that A obj has B in its structure
var book = from b in books
where book.Id in ( from ab in AuthersBooks
where selectedAuthers.contains(ab.AutherId)
select ab.bookId ) //now we have books that are authered by one of the selected authers
select new { BookId = b.Id, // now we create an anonymos object to contain any info we need
BookName = b.Name,
BookAuthers = (from a in authers
join ab in AuthersBooks
on a.Id == ab.AuthersId
where ab.bookid == b.Id
select a)
this will propably have syntax errors and after correcting you may get an error about multiple threads which already has an answer here

Related

Orderby() in tri-level entity structure

I have 3 entities that all encompass eachother. MakeSource can have many ModelSources and ModelSources can have many YearSources. The data I am retrieving looks like this:
So far I can only order by Makes and not models or years.
var data = context.MakeSources.OrderBy(P => P.Name).Include(A => A.ModelSources
.Select(B => B.YearSources));
Placing more OrderBy calls within the include throws errors. My question is:
How can I get a neatly ordered collection of first Makes ordered by asc, for each make its models ordered by ascending and for each model its years ordered by ascending?
I tried using ThenBy() but then I cannot access nested properties of ModelSource
var data = context.MakeSources.Include(A => A.ModelSources
.Select(B => B.YearSources)).OrderBy(P => P.Name).ThenBy(p => p.ModelSources.
I re-created your situation in my sandbox database, and wrote a linq query like this. This gives you a list of makes, models, and years. I used cars, but i really don't know what your data looks like.
var data = (from a in ctx.MakeSources
join b in ctx.ModelSources on a.Id equals b.MakeSourceId
join c in ctx.YearSources on b.Id equals c.ModelSourceId
orderby a.Name, b.Name, c.Year
select new { Make = a.Name, Model = b.Name, Year = c.Year }).ToArray();
This will give you a flat list
To order them in collections, such as each make has a collection of models, and models have a collection of years, I did this.
var data = (from a in ctx.MakeSources
orderby a.Name
select new
{
Make = a.Name,
Models = (from b in ctx.ModelSources
where b.MakeSourceId == a.Id
orderby b.Name
select new
{
Model = b.Name,
Years = (from c in ctx.YearSources
where c.ModelSourceId == b.Id
orderby c.Year
select new { ModelYear = c.Year })
})
}).ToArray();
I am not aware of any easy way to do it using just includes and .OrderBy()s as it preloads the navigation properties, and the result in the include method has to be a collection of entities, as far as I am aware. So returning an ordered list won't load the entities (as evident by the error you received)

LINQ - How to select and count the right results

I have 3 tables: DiaryPosts, DiaryImpressions, Impressions.
Impressions is a small list with some fields: 'like', 'dislike', 'agree', 'disagree'. The user can vote according to what he thinks about the post.
DiaryImpressions is the table that handles the relationship between the posts and the users who vote.
My problem is, I have to count results of each impression vote for each post, so maybe for one post 13 users voted for like, 2 for dislike, 34 agree and 1 disagree.
I have no idea how to perform the query in some way I can get this specific count results for each impression.
Can anyone help me with that?
You can do this via the GroupBy method. It allows you to automatically "group" the elements based on the impression, and count the results per group.
var post(from c in posts selec c)
string post1like;
string post2dislike;
string postagree3;
string postdisagree3;
foreach (var item in posts)
{
var ipressionslike=(from c in imressions where impressioid=item.id where c.impressionID='LIKE' select c.userID).Tolist()
var ipressionsdislike=(from c in imressions where impressioid=item.id where c.impressionID='disLIKE' select c.userID).Tolist()
var ipressionslike=(from c in imressions where impressioid=item.id where c.impressionID='LIKE' select c.userID).Tolist()
var ipressionsagree=(from c in imressions where impressioid=item.id where c.impressionID='disLIKE' select c.userID).Tolist()
post1like+=item.id+""+ipressionsdislike.count;
post2dislike+=item.id+""+ipressionslike.count;
postagree3+=item.id+""+ipressionsagree.count;
}
it should count the impressions for each post and count the amount of users that like or dislike so if you have 30 people dislike for each post it should get them I cannot see your table structure but I hope it will help or point you somewhere
I have to guess but here is what I think the SQL would look like:
SELECT I.Name, COUNT(I.Name)
FROM DairyPosts P
JOIN DairyImpressions DI ON P.ID=DI.DairyID
JOIN Impressions I ON DI.ImpressionsID = I.ID
And what the linq would look like:
List<Dairy> dairyposts = GetDairyPosts();
var impressionCounts =
from p in dairyposts
group p by p.ImpressionName into g
select new { Type = g.Key, ImpressionCount = g.Count() };
Of course I have to assume your list is created a certain way, if you can post how your list is actually created that would help. (As I said in the comments)

Subquery nightmares in EF

I'm really, really struggling with what should otherwise be a straightforward query in anything other than LINQ (for example SQL!)
I have two entities:
Product
ProductApprover
The Product entity has a one to many relationship on the ProductApprover entity, e.g:
Product.ProductApprovers gives me all ProductApprover entities relating to the Product.
Getting a Product and associated ProductApprover data is simple enough when querying by my ProductID column on my Product entity as the ProductApprover data associated is bundled into the result automatically, but my problem comes when I want to alter my query by querying data WITHIN my associated ProductApprover entities. I have tried all sorts with use of the 'Where', 'Contains' and 'Any', functions, etc, to perform a subquery, but cannot seem to get the result I want.
The query I want to perform is:
SELECT * FROM Product p
INNER JOIN ProductApprover pa ON p.ProductId = pa.ProductId
WHERE p.ProductId = #id AND pa.Version = #version
Can anybody help me out please? Thank you kindly in advance.
Try this (I guess this is a LINQ interpretation of your SQL query):
int id = 123;
int version = 555;
var results = from p in context.Products
join pa in context.ProductApprovers
on p.ProductId = pa.ProductId
where p.ProductId equals id && pa.Version equals version
select new { Product = p, Approver = pa };
I suspect you want something like this:
var query = from product in db.Products
where product.ProductId == productId
select new {
Product = product,
Approvers = product.Approvers.Where(pa => pa.Version == version)
};
If that doesn't do what you want, could you explain where it falls down?

LINQ Query Similar to SQL WHERE x IN

I have a need to create a LINQ query that returns results based on a subquery. Not quite sure I'm wording that properly but the best way I know to ask is to show an example. How can I turn the following TSQL query into a LINQ query (tables are same name as objects):
SELECT CuisineId, Name
FROM Cuisine
WHERE CuisineId NOT IN (SELECT CuisineId
FROM RestaurantCuisine
WHERE RestaurantId = #id)
As you can guess, I'm trying to get a list of "available" cuisines to be listed for a user to add to a list of cuisines that a restaurant offers. The LINQ I have thus far returns ALL cuisines and doesn't take in account of the existing CuisineId's that have already been added to the other table:
I've looked all over for an example but not quite sure how to describe exactly what I need. I looked at the MSDN reference for LINQ queries but couldn't find anything like what I need:
MSDN LINQ Sample Queries
Anyone able to give me an example?
In C#:
var query =
from c in db.Cuisine
where !(from rc in db.RestaurantCuisine
where rc.RestaurantId == id
select rc.CuisineId)
.Contains(c.CuisineId)
select new {
c.CuisineId,
c.Name
};
In VB.NET:
Dim availableCuisines = _
From c In db.Cuisines _
Where Not (From rc In db.RestaurantCuisines _
Where rc.RestaurantId = id _
Select rc.CuisineId) _
.Contains(c.CuisineId) _
Select c
var cuisines = db.Cuisine.Where(c => !RestaurantCuisine.Any(
rc => rc.RestaurantId == c.Id && rc.CuisineId == c.CuisineId);
Try:
Cuisine.Where(c => !RestaurantCuisine.Select(rc => rc.CuisineID).Contains(c.CuisineID)).Select(c => c);
var query = (from c in Cuisine
where !(from rest in RestaurantCuisine
where (rest.RestaurantID == id)).Contains(c.CuisineId)
select new
{
CuisineID = c.CuisineID,
Name = c.Name
});

ef and linq extension method

I have this sql that i want to have written in linq extension method returning an entity from my edm:
SELECT p.[Id],p.[Firstname],p.[Lastname],prt.[AddressId],prt.[Street],prt.[City]
FROM [Person] p
CROSS APPLY (
SELECT TOP(1) pa.[AddressId],a.[ValidFrom],a.[Street],a.[City]
FROM [Person_Addresses] pa
LEFT OUTER JOIN [Addresses] AS a
ON a.[Id] = pa.[AddressId]
WHERE p.[Id] = pa.[PersonId]
ORDER BY a.[ValidFrom] DESC ) prt
Also could this be re-written in linq extension method using 3 joins?
Assuming you have set the Person_Addresses table up as a pure relation table (i.e., with no data besides the foreign keys) this should do the trick:
var persons = model.People
.Select(p => new { p = p, a = p.Addresses.OrderByDescending(a=>a.ValidFrom).First() })
.Select(p => new { p.p.Id, p.p.Firstname, p.p.LastName, AddressId = p.a.Id, p.a.Street, p.a.City });
The first Select() orders the addresses and picks the latest one, and the second one returns an anonymous type with the properties specified in your query.
If you have more data in your relation table you're gonna have to use joins but this way you're free from them. In my opinion, this is more easy to read.
NOTE: You might get an exception if any entry in Persons have no addresses connected to them, although I haven't tried it out.

Resources