Making joins in Entity Framework with not mapped tables - c#

I need help: I need to make a join with 3 tables, but one of it was not mapped by Entity Framework because is just a relational table the join I need is something like that:
select *
from Promocao p
join ProdutoPromocao as pp on pp.PromocaoId = p.IdPromocao
join Produto as pr on pp.ProdutoId = pr.IdProduto
join Boteco as b on pr.botecoId = b.IdBoteco
where b.IdBoteco = 1
but the table ProdutoPromocao was not mapped, how can I do this with Entity Framework?
I thought about something like:
(from pr in db.Promocao
join p in db.Produto on (pr.Produto.Select(x=>x.IdProduto)) equals p.IdProduto //this line is not working, I would need something like pr.Produto.IdProduto but it does not offer me this alternative
join b in db.Boteco on p.BotecoId equals b.IdBoteco
where b.IdBoteco == idBoteco
select pr
).ToList();
Someone please help me.

You can try as shown below.
(from pr in db.Promocao
join p in db.Produto on (pr.Produto.Select(x=>x.IdProduto).FirstOrDefault()) equals p.IdProduto
join b in db.Boteco on p.BotecoId equals b.IdBoteco
where b.IdBoteco == idBoteco
select pr
).ToList();

When working with EF, there is no need to (and in some cases like this you can't) use manual joins. Once you have navigation properties, all you need is to use them (like if they were objects) and EF will generate the necessary joins for you.
Your query should be something like this:
from pr in db.Promocao
from p in pr.Produto
let b = p.Boteco
... (the rest)

Related

Linq to Sql multiple outer joins

Thanks in advance for any help.
Not an expert in Linq to Sql by any means.
I have 4 tables.
The main lb_item table which defines, unsurprisingly, an item.
Many fields but holds 3 ID fields.
itemID (key)
categoryID (not null)
patternID (can be null)
lb_pattern table which is keyed off the lb_item patternID.
lb_category table which is keyed off the lb_item categoryID.
lb_animal table which is keyed off the lb_item item ID.
So I need a select from the lb_item table joining to these other 3 tables to bring back varchar fields as I'm building a DTO.
A single left outer join works fine thus:
from lbi in lbContext.lb_item
join lbp in lbContext.lb_pattern on lbi.patternID equals lbp.patternID into g1
from j1 in g1.DefaultIfEmpty()
join lbc in lbContext.lb_category on lbi.categoryID equals lbc.categoryID
where lbi.itemID == id
select new lb_itemDTO..........
I now need to add a 2nd left outer join for the lb_animal table.
So I started to do this:
from lbi in lbContext.lb_item
join lbp in lbContext.lb_pattern on lbi.patternID equals lbp.patternID into g1
from j1 in g1.DefaultIfEmpty()
join lba in lbContext.lb_animal on j1.
But the options in VS for j1 give me only the fields within the lb_pattern table.
I need the join to read:
join lba in lbContext.lb_animal on j1.itemID equals lba.itemID
or
join lba in lbContext.lb_animal on lbi.itemID equals lba.itemID
Neither works and gives me an exception along the lines of "'NavigationExpandingExpressionVisitor' failed. This may indicate either a bug or a limitation in EF Core".
So how can I add a left outer join to the lb_animal table?
I've spent the last hour looking at various SO posts to suss it out but I just cannot seem to get my head around the solution for some reason. Feel like a newbie. And I'm sure the solution is going to be obvious!
Any help or pointers to a solution would be much appreciated.
This should work:
var ans = from lbi in lbContext.lb_item
where lbi.itemID == id
join lbp in lbContext.lb_pattern on lbi.patternID equals lbp.patternID into lbpj
from lbp in lbpj.DefaultIfEmpty()
join lba in lbContext.lb_animal on lbi.itemID equals lba.itemID into lbaj
from lba in lbaj.DefaultIfEmpty()
join lbc in lbContext.lb_category on lbi.categoryID equals lbc.categoryID
select new {
};
Persvered and finally came across a SO post which approached it in a different way and it worked.
Original SO is here:
My working code is now thus:
from lbi in lbContext.lb_item
from lbc in lbContext.lb_category
.Where(c => c.categoryID == lbi.categoryID)
from lbp in lbContext.lb_pattern
.Where(p => p.patternID == lbi.patternID)
.DefaultIfEmpty()
from lba in lbContext.lb_animal
.Where(a => a.itemID == lbi.itemID)
.DefaultIfEmpty()
where lbi.itemID == id
select new lb_itemDTO
Would still be interested in comments on this solution as it's not breaking the outer joins into grouped segments. So is this solution I found any less efficient in terms of the SQL it generates compared to how I was originally proposing to do it?

EF core 2.1 select/distinct

I'm using sql profiler to see sql generated by Ef core2.1,
this is my linq query :
var resulat = (from a in A
join b in B equals a.level=b.level
where ...
select new M1 {AId = a.id}).Distinct();
(from r in resulat
join c in C equals r.AId = c.AId
select new M2
{
CId = c.Id,
level = _helper(c.level)
}).Distinct();
Sql generated:
select t.AId,c.Id,c.level
from
(
select distinct a.id
from A a
inner join B b on a.level=b.level
where ...
) as t
inner join C c on t.AId = c.AId
What i want as result is :
select distinct c.Id,c.level
from
(
select distinct a.id
from A a
inner join B b on a.level=b.level
where ...
) as t
inner join C c on t.AId = c.AId
I have tried also using select/distinct with result IQueryable, but the sql generated is the same.
what i missed in my linq query or what i have to add to have this sql query
That's what worked for me:
Delete Distinct() from result query, this avoid adding t.AId to my selection.
Delete a helper method from one of my selection fields performe adding Distinct() to final query.
This is my query after correction:
var resulat = from a in A
join b in B equals a.level=b.level
where ...
select new M1 {AId = a.id};
(from r in resulat
join c in C equals r.AId = c.AId
select new M2
{
CId = c.Id
level = c.level
}).Distinct();
Many thanks for your comments, it really helped me.
I'm always a fan of querying the data you want directly from the table (well, DbSet) that returns the data. The process looks a bit like these steps:
I want C.Id and C.Level
That's context.Cs.
Which Cs do I want?
The ones that have a parent A, of which at least one B has the same 'level' as A and meets a couple of other criteria (the where ...).
That amounts to:
from c in context.Cs
where context.Bs.Any(b => b.level == c.A.level && <other criteria>)
select new { c.Id, c.Level }
If the where ... also contains filter criteria for A you can add predicates like && c.A == ... to the where.
Note that I assume a navigation property c.A to be present, otherwise to be created, because C has AId.

Multiple Table Join in Linq C# Dynamically

I have 3 data tables: a; b; and c. In this I need to write Join Query Dynamically using LINQ.
The Selecting columns given by customer and Condition columns also given customer at run time.
So I need to create queries dynamically. Please check below example. Because I don't know which table they want and which column also
For example
Select a.c1,a.c2,b.c1,b.c2 From a Left Join b on a.c1=b.c1
Select c.c1,c.c2,a.c1,a.c2 From c Left Join a on c.c3=a.c1
Select a.c1,a.c2,b.c1,b.c2,c.c1,c.c2 From a Left Join b on a.c2=b.c2 Left join c on c.c1=a.c1
Like I need create different set of queries. Please help me on this.
You could use either System.Linq.Dynamic(ScottGu's blog article and nuget) in case of dynamic where clause:
var results = (from fruit in fruits
join car in cars on fruit.Id equals car.Id
select new { fruit, car })
.AsQueryable()
.Where("fruit.ColA != car.ColA")
.Where("fruit.ColB == car.ColB");
Or dynamicaly build expressions this using extensions from PredicateBuilder writen by #joe-albahari. For example:
var predicate =
PredicateBuilder
.True<Tuple<Product, Product>>()
.And(t => t.Item1.ColA != t.Item2.ColA)
.And(t => t.Item1.ColB == t.Item2.ColB)
.Compile();
(from fruit in fruits
join car in cars on fruit.Id equals car.Id
select Tuple.Create(fruit, car))
.Where(predicate)
.Dump();
ps: full code available at gisthub

Left join in Linq?

There are a lot of questions on SO already about Left joins in Linq, and the ones I've looked at all use the join keyword to achieve the desired end.
This does not make sense to me. Let's say I have the tables Customer and Invoice, linked by a foreign key CustomerID on Invoice. Now I want to run a report containing customer info, plus any invoices. SQL would be:
select c.*, i.*
from Customer c
left join Invoice i on c.ID = i.CustomerID
From what I've seen of the answers on SO, people are mostly suggesting:
var q = from c in Customers
join i in Invoices.DefaultIfEmpty() on c.ID equals i.CustomerID
select new { c, i };
I really don't understand how this can be the only way. The relationship between Customer and Invoice is already defined by the LinqToSQL classes; why should I have to repeat it for the join clause? If I wanted an inner join it would simply have been:
var q = from c in Customers
from i in c.Invoices
select new { c, i };
without specifying the joined fields!
I tried:
var q = from c in Customers
from i in c.Invoices.DefaultIfEmpty()
select new { c, i };
but that just gave me the same result as if it were an inner join.
Is there not a better way of doing this?
While the relationship is already defined (both in the database and in the .dbml markup) the runtime cannot automatically determine if it should use that relationship.
What if there are two relationships in the object model (Person has Parents and Children, both relationships to other Person instances). While cases could be special cased, this would make the system more complex (so more bugs). Remember in SQL you would repeat the specification of the relationship.
Remember indexes and keys are an implementation detail and not part of the relational algebra that underlies the relation model.
If you want a LEFT OUTER JOIN then you need to use "into":
from c in Customers
join i in Invoices on i.CustomerId equals c.CustomerId into inv
...
and inv will have type IEnumerable<Invoivce>, possibly with no instances.
What are you talking about? That from i in c.Invoice.DefaultIfEmpty() is exactly a left join.
List<string> strings = new List<string>() { "Foo", "" };
var q = from s in strings
from c in s.DefaultIfEmpty()
select new { s, c };
foreach (var x in q)
{
Console.WriteLine("ValueOfStringIs|{0}| ValueOfCharIs|{1}|",
x.s,
(int)x.c);
}
This test produces:
ValueOfStringIs|Foo| ValueOfCharIs|70|
ValueOfStringIs|Foo| ValueOfCharIs|111|
ValueOfStringIs|Foo| ValueOfCharIs|111|
ValueOfStringIs|| ValueOfCharIs|0|
You may probably want to use the 'into' keyword.
Example

What is the syntax for an inner join in LINQ to SQL?

I'm writing a LINQ to SQL statement, and I'm after the standard syntax for a normal inner join with an ON clause in C#.
How do you represent the following in LINQ to SQL:
select DealerContact.*
from Dealer
inner join DealerContact on Dealer.DealerID = DealerContact.DealerID
It goes something like:
from t1 in db.Table1
join t2 in db.Table2 on t1.field equals t2.field
select new { t1.field2, t2.field3}
It would be nice to have sensible names and fields for your tables for a better example. :)
Update
I think for your query this might be more appropriate:
var dealercontacts = from contact in DealerContact
join dealer in Dealer on contact.DealerId equals dealer.ID
select contact;
Since you are looking for the contacts, not the dealers.
And because I prefer the expression chain syntax, here is how you do it with that:
var dealerContracts = DealerContact.Join(Dealer,
contact => contact.DealerId,
dealer => dealer.DealerId,
(contact, dealer) => contact);
To extend the expression chain syntax answer by Clever Human:
If you wanted to do things (like filter or select) on fields from both tables being joined together -- instead on just one of those two tables -- you could create a new object in the lambda expression of the final parameter to the Join method incorporating both of those tables, for example:
var dealerInfo = DealerContact.Join(Dealer,
dc => dc.DealerId,
d => d.DealerId,
(dc, d) => new { DealerContact = dc, Dealer = d })
.Where(dc_d => dc_d.Dealer.FirstName == "Glenn"
&& dc_d.DealerContact.City == "Chicago")
.Select(dc_d => new {
dc_d.Dealer.DealerID,
dc_d.Dealer.FirstName,
dc_d.Dealer.LastName,
dc_d.DealerContact.City,
dc_d.DealerContact.State });
The interesting part is the lambda expression in line 4 of that example:
(dc, d) => new { DealerContact = dc, Dealer = d }
...where we construct a new anonymous-type object which has as properties the DealerContact and Dealer records, along with all of their fields.
We can then use fields from those records as we filter and select the results, as demonstrated by the remainder of the example, which uses dc_d as a name for the anonymous object we built which has both the DealerContact and Dealer records as its properties.
var results = from c in db.Companies
join cn in db.Countries on c.CountryID equals cn.ID
join ct in db.Cities on c.CityID equals ct.ID
join sect in db.Sectors on c.SectorID equals sect.ID
where (c.CountryID == cn.ID) && (c.CityID == ct.ID) && (c.SectorID == company.SectorID) && (company.SectorID == sect.ID)
select new { country = cn.Name, city = ct.Name, c.ID, c.Name, c.Address1, c.Address2, c.Address3, c.CountryID, c.CityID, c.Region, c.PostCode, c.Telephone, c.Website, c.SectorID, Status = (ContactStatus)c.StatusID, sector = sect.Name };
return results.ToList();
You create a foreign key, and LINQ-to-SQL creates navigation properties for you. Each Dealer will then have a collection of DealerContacts which you can select, filter, and manipulate.
from contact in dealer.DealerContacts select contact
or
context.Dealers.Select(d => d.DealerContacts)
If you're not using navigation properties, you're missing out one of the main benefits on LINQ-to-SQL - the part that maps the object graph.
Use Linq Join operator:
var q = from d in Dealer
join dc in DealerConact on d.DealerID equals dc.DealerID
select dc;
basically LINQ join operator provides no benefit for SQL. I.e. the following query
var r = from dealer in db.Dealers
from contact in db.DealerContact
where dealer.DealerID == contact.DealerID
select dealerContact;
will result in INNER JOIN in SQL
join is useful for IEnumerable<> because it is more efficient:
from contact in db.DealerContact
clause would be re-executed for every dealer
But for IQueryable<> it is not the case. Also join is less flexible.
Actually, often it is better not to join, in linq that is. When there are navigation properties a very succinct way to write your linq statement is:
from dealer in db.Dealers
from contact in dealer.DealerContacts
select new { whatever you need from dealer or contact }
It translates to a where clause:
SELECT <columns>
FROM Dealer, DealerContact
WHERE Dealer.DealerID = DealerContact.DealerID
Inner join two tables in linq C#
var result = from q1 in table1
join q2 in table2
on q1.Customer_Id equals q2.Customer_Id
select new { q1.Name, q1.Mobile, q2.Purchase, q2.Dates }
Use LINQ joins to perform Inner Join.
var employeeInfo = from emp in db.Employees
join dept in db.Departments
on emp.Eid equals dept.Eid
select new
{
emp.Ename,
dept.Dname,
emp.Elocation
};
Try this :
var data =(from t1 in dataContext.Table1 join
t2 in dataContext.Table2 on
t1.field equals t2.field
orderby t1.Id select t1).ToList();
OperationDataContext odDataContext = new OperationDataContext();
var studentInfo = from student in odDataContext.STUDENTs
join course in odDataContext.COURSEs
on student.course_id equals course.course_id
select new { student.student_name, student.student_city, course.course_name, course.course_desc };
Where student and course tables have primary key and foreign key relationship
try instead this,
var dealer = from d in Dealer
join dc in DealerContact on d.DealerID equals dc.DealerID
select d;
var Data= (from dealer in Dealer join dealercontact in DealerContact on dealer.ID equals dealercontact.DealerID
select new{
dealer.Id,
dealercontact.ContactName
}).ToList();
var data=(from t in db.your tableName(t1)
join s in db.yourothertablename(t2) on t1.fieldname equals t2.feldname
(where condtion)).tolist();
var list = (from u in db.Users join c in db.Customers on u.CustomerId equals c.CustomerId where u.Username == username
select new {u.UserId, u.CustomerId, u.ClientId, u.RoleId, u.Username, u.Email, u.Password, u.Salt, u.Hint1, u.Hint2, u.Hint3, u.Locked, u.Active,c.ProfilePic}).First();
Write table names you want, and initialize the select to get the result of fields.
from d1 in DealerContrac join d2 in DealerContrac on d1.dealearid equals d2.dealerid select new {dealercontract.*}
One Best example
Table Names : TBL_Emp and TBL_Dep
var result = from emp in TBL_Emp join dep in TBL_Dep on emp.id=dep.id
select new
{
emp.Name;
emp.Address
dep.Department_Name
}
foreach(char item in result)
{ // to do}

Categories

Resources