linq operators like in - asp.net-mvc

HI,
I have 3 tables: Clips, Books and relationships between ClipBook
Problem is:
i need get book that has bookID=4 with some clips i mean many-to-many
in simple text sql it will be something like this:
select * from Clips where clipID in (select clipID from ClipBook where bookID=4)
Question is:
How can i do this with Linq without operator Join of course

this could be a solution;
from cb in ClipBooks
where cb.BookID == 4
select cb.Clip;
or
ClipBooks.Where(cb => cb.BookId == 4).Select(cb => cb.Clip);

the Contains method is in Linq converted into the IN operator, example:
String[] cities = {"London", "Paris", "Madrid"};
from p in context.Person
where cities.Contains(p.Adress.City)
select p
is translated into a sql clause like: .. WHERE a.City in ('London', 'Paris', 'Madrid') where a is the Address table alias after the join with the Person table.
edit:
you could write a single query without a subquery, but this will be converted to a join most probably:
var clips = (from c in context.ClipBooks
where c.BookID == 4
select c.Clip).Distinct();
or
var clips = from c in context.Clip
where c.ClicBooks.Any( cb => cb.BookID == 4)
select c
Any is translated in Exists()

Related

F# query expression: How to do a left join and return on those records where the joined table is null?

I am using SQLProvider in a project and I would like to run a query with a left join and return all records that are missing from the joined table.
I suspect the answer to this question will involve one or both of the packages FSharp.Data.TypeProviders and FSharpComposableQuery, although, to be honest, I can't tell where one ends and the other begins.
The common example of a left join in the above links is given as
query {
for student in db.Student do
leftOuterJoin selection in db.CourseSelection
on (student.StudentID = selection.StudentID) into result
for selection in result.DefaultIfEmpty() do
select (student, selection)
}
And from what I can tell, this is equivalent to the sql:
select *
from Student s
left outer join CourseSelection cs on s.StudentID = cs.StudentID
But what I am looking for is the F# equivalent of the sql:
select *
from Student s
left outer join CourseSelection cs on s.StudentID = cs.StudentID
where s.StudentID is null
I realize that I can just return all records and then filter them in F#, but I want the filtering to happen on the database side where things are indexed and because, in my case especially, the number of non null records is huge, and I am only interested in the null ones.
I think this should do the trick:
query {
for student in db.Student do
leftOuterJoin selection in db.CourseSelection
on (student.StudentID = selection.StudentID) into result
where (not (result.Any()))
select student
}
or a nested query:
query {
for student in db.Student do
where (query {
for selection in db.CourseSelection do
all (student.StudentID <> selection.StudentID)
})
select student
}
Edit: since you're using FSharp.Data.TypeProviders, if you have a foreign key between these two tables then you should also have a property that gives the associated CourseSelections, something like this:
query {
for student in db.Student do
where (not (student.CourseSelections.Any()))
select student
}

How to deal with Null Values in OUTER JOINS using Entity Framework 6

I need to process the query at the bottom of this post in C#. The query works, but I don't know how to use it in EF6. I used a method and a viewmodel for it (variable query = the query below). But when it encounters null values in the OUTER JOIN, int32 cant accept this value when calling .toList(). What's the best way to deal with it?
var result = context.Database.SqlQuery<TourQueryViewModel>(query);
var reslist = result.ToList();
I tried my first steps with LINQ, but I dont get it how to translate into LINQ itself or the query-methods, that are equivalent to it. So I am hoping for your help.
SELECT toursdata.TourId AS TourId, toursdata.Tourname AS Tourname,toursdata.Tourdate Tourdate,
toursdata.VehicleId AS VehicleId, toursdata.VehicleName AS VehicleName, toursdata.LicenseNumber AS LicenseNumber,
Employees.EmployeeId AS EmployeeId, Employees.Gender AS Gender, Employees.Forename AS Forename, Employees.Surname AS Surname
FROM (
SELECT te.TourId, te.Tourname, te.Tourdate,
Vehicles.VehicleId, Vehicles.VehicleName, Vehicles.LicenseNumber,
TourEmployees.EmployeeId
FROM TourEmployees RIGHT OUTER JOIN Tours AS te ON TourEmployees.TourId = te.TourId,
Tours AS tv INNER JOIN Vehicles ON tv.VehicleId = Vehicles.VehicleId
WHERE tv.TourId = te.TourId
) toursdata
LEFT OUTER JOIN Employees ON toursdata.EmployeeId = Employees.EmployeeId
To eliminate the null problem, I changed the data type of the corresponding entity-attribute to a nullable-type
int turned to int?.
Didnt know about that language feature.

F# query for join/group/aggregate?

How can I get F# to do the equivalent of
select a.id, avg(case when a.score = b.score then 1.0 else 0.0 end)
from table1 a join table2 b on a.id = b.id and a.date = b.date
group by a.id
in a query expression? I've come up with
query {
for a in db.table1 do
join b in db.table2 on ((a.id, a.date) = (b.id, b.date))
groupBy a.id into g
select (g.Key, ???) }
but I can't figure out what to insert into "???". To make things worse, the "score" column can be null, which complicates the math.
Alternatively, is there an easier way to do this? I'm not very familiar with .NET database access. Ideally, I'd just give it a block of SQL, it would parse it, and spit back some typed data. As it is, trying to figure out the not-SQL syntax for straightforward SQL is pretty frustrating.
The translation to SQL can generally deal better with C#-style LINQ operations than with native F# functions. So it is easier to go with Select and Average extension methods than with standard F# functions like Seq.map and Seq.average.
I tried writing a similar grouping using a sample Northwind database - I did not find nice tables to join, but the following does basic aggregation with CASE and works fine:
open System.Linq
query {
for p in db.Products do
groupBy p.CategoryID.Value into g
select (g.Key, g.Select(fun a ->
if a.UnitPrice.Value > 10.0M then 1.0 else 0.0).Average()) }
|> Array.ofSeq
It generates a query that is a bit more complicated, but looks right (and uses CASE on the SQL side). You can see that by setting db.DataContext.Log <- System.Console.Out.
Another thing that should generally work would be to use nested query, but I have not tried that.
Some years now, but never too late? Is this of any help? In particular, note the use of FirstOrDefault. Sorry for the Norwegian names, but that's not important. The "x" demonstrates access to the first table.
type Result3 = { Aarsak: int; Beskrivelse: string; Antall: int; Varighet: Nullable<int> }
let query3 = query {
for stopptid in dc.StoppTider do
where (stopptid.DatoS = datoS && stopptid.SkiftNr = skiftNr)
groupBy stopptid.Aarsak into g
join stoppaarsak in dc.StoppAarsak on (g.FirstOrDefault().Aarsak.ToString() = stoppaarsak.Nr)
select { Aarsak = g.Key; Beskrivelse = stoppaarsak.Norsk; Antall = g.Count(); Varighet = g.Sum(fun x -> x.Varighet) }
}
I first ended up here when googling. Since it didn't help, I googled equivalent solutions in C#, got a hit on SO, got that to work for my case in C#, then in F#. This is the link:
LINQ: combining join and group by

EF4 Cascading Left Outer Joins Null Exception

I have this query
Select p.Name,p.Street from person p
left join address a on a.address_id = p.address_id
left join Order o on o.order_id = a.order_id
But when i try to convert it into LINQ query,
var q = from p in Entities.Person
from a in Entities.Address.Where(a=>a.address_id == p.address_id).DefaultIfEmpty()
from o in Entities.Order.Where (o=>o.order_id== a.order_Id).DefaultIfEmpty()
I am getting a Null exception since for some combination of address_ids there are no addresses and it blows up in o=>o.order_id== a.order_Id clause(since a is null).
Please let me know how to do multiple left joins in EF 4, the correct way !
Thanks !
If you have modeled correctly you do not need to explicitly do left outer joins.
Select p.Name, a.Street from person p
left join address a on a.address_id = p.address_id
left join Order o on o.order_id = a.order_id
The above query can be converted as follows
var projection = Entities.Person.Select(p => new {p.Name, p.Address.Street});
EF will automatically add the joins to retrieve the fields.
You can manually do the joins as follows
var projection = from p in Entities.Person
join a in Entities.Address on p.address_id equals a.address_id into outer
from a in outer.DefaultIfEmpty()
select new {p.Name, a.Street};

Convert Left outer join query into Entity Framework query

I have a sql statement that I want to be able to convert into EF4.
Its a simple Left outer join that looks like
SELECT *
FROM EntryDate
LEFT OUTER JOIN Member on Member.CardId = EntryDate.CardID
how do I do this using the entity framework 4?
If there is relation mapped in your model you can simply use navigation properties because they always use left join:
var data = members.EntryDates;
I expect you don't have such relation because CardId doesn't look like primary key of Member or EntryDate.
If you don't have navigation properties you must use
var query = from m in context.Members
join e in context.EntryDates on m.CardId equals e.CardId into x
from res in x.DefaultIfEmpty()
select new
{
Member = m,
EntryDate = res
};
This works only in EFv4+ because EFv1 didn't support DefaultIfEmpty.

Resources