Recursive Joins with Linq - c#

I am using LinqToDB to help query a SQLite Database, however, I am having an issue where I need to do a join in a collection of joins. Here is what I have so far.
var craftList = from c in db.GetTable<Craft>()
join cP in db.GetTable<CraftProduct>() on c.ID equals cP.CraftID into cPS
join cM in db.GetTable<CraftMaterial>() on c.ID equals cM.CraftID into cMS
select new
{
Craft = c,
CraftProducts = cPS,
CraftMaterials = cMS
};
I need to do add to the groups cPS & cMS and have each element join with another table. Here is an example query that kind of shows you what needs to be done with the elements in cMS.
var materialList = from cM in db.GetTable<CraftMaterial>()
join i in db.GetTable<Item>() on cM.ItemID equals i.ID
select CraftMaterial.Build(cM, i);

I was able to figure out what I needed to do after some messing around, I just needed to do multiple queries.
var craftList = from craft in db.GetTable<Craft>()
join craftProduct in db.GetTable<CraftProduct>() on craft.ID equals craftProduct.CraftID into
craftProducts
join craftMaterial in db.GetTable<CraftMaterial>() on craft.ID equals craftMaterial.CraftID into
craftMaterials
select new
{
Craft = craft,
CraftProducts = from craftProduct in craftProducts
join item in db.GetTable<Item>() on craftProduct.ItemID equals item.ID
select CraftProduct.Build(craftProduct, item),
CraftMaterials = from craftMaterial in craftMaterials
join item in db.GetTable<Item>() on craftMaterial.ItemID equals item.ID
select CraftMaterial.Build(craftMaterial, item)
};

Related

Join list with table in linq

I have a problem. I get all data in var type variable and then want to apply a join with database table in code first approach. Facing problem, lot of search on internet and apply but failed.
var joinedData =
from menuGroup in _menuGroupMenusRepository.GetAll()
.Where(x => x.GroupId == input.GroupId)
join menus in _menuRepository.GetAll()
on menuGroup.MenuId equals menus.Id
join categSubcateg in _menuCategSubCategRepository.GetAll()
on menus.Id equals categSubcateg.MenuId
join categ in _menuCategoryRepository.GetAll()
on categSubcateg.CategoryId equals categ.Id
select new
{
CategoryId = categSubcateg.CategoryId,
CategoryName = categ.Category,
};
Now I want joinedData variable join with MainMenuSort table.
MainMenuSort table also have groupid and categoryid.
to perform join you just need to do as below
var q=(from jd in joinedData
join mms in dataContext.MainMenuSort
on jd.CategoryId equals mms.CategoryId
select jd).ToList();
if its datatable then
var q=(from jd in joinedData
join mms in dtMainMenuSort.AsEnumerable()
on jd.CategoryId equals mms.Field<int>("CategoryId")
select jd).ToList();

C# - Join Syntax with two tables [duplicate]

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}

How to perform a left join with an additional filtering in LINQ to entities?

I have several tables, the main one is called DefectRecord, others are called DefectArea, DefectLevel...etc and the one called DefectAttachment. And this problem is about joining DefectRecord with other tables to get a ViewModel for further use. What the hard part I am facing is about the DefectAttachment table.
DefectRecord has a 1-to-many relation with DefectAttachment. While there may be NO attachment at all for one defect record, there may be multiple attachments.
Logically I tried to perform a left join among DefectRecord & DefectAttachment, but there is one more requiredment:
If there is multiple attachments, select ONLY the oldest one(i.e. the
one with oldest CreatedDate field value)
I am stuck at this requirement, how can I perform this with LINQ-to-Entities? Below is the code of what I have now:
var ret = (from dr in defectRecordQuery
join ft in filterQuery on dr.FilterID equals ft.FilterID
join l in levelQuery on dr.LevelID equals l.LevelID
join a in attachmentQuery on dr.DefectRecordID equals a.DefectRecordID into drd
from g in drd.DefaultIfEmpty()
select new DefectRecordViewModel
{
DefectRecordCode = dr.Code,
DefectAttachmentContent = g == null ? null : g.FileContent,
LookupFilterName = ft.FilterName,
}).ToList();
The *Query variable are the IQueryable object which get the full list of corresponding table.
Group your results by the Code and FilterName and then for the content take that of the item in the group that has the oldest date
var ret = (from dr in defectRecordQuery
join ft in filterQuery on dr.FilterID equals ft.FilterID
join l in levelQuery on dr.LevelID equals l.LevelID
join d in attachmentQuery on dr.DefectRecordID equals d.DefectRecordID into drd
from g in drd.DefaultIfEmpty()
group g by new { dr.Code, ft.FilterName } into gg
select new DefectRecordViewModel
{
DefectRecordCode = gg.Key.Code,
DefectAttachmentContent = gg.OrderByDescending(x => x.CreateDateTime).FirstOrDefault() == null? null: gg.OrderByDescending(x => x.CreateDateTime).FirstOrDefault().FileContent,
LookupFilterName = gg.Key.FilterName,
}).ToList();
If using C# 6.0 or higher then you can do:
DefectAttachmentContent = gg.OrderByDescending(x => x.CreateDateTime)
.FirstOrDefault()?.FileContent,

Can't access the fields of non-grouping tables in linq

I'm trying to join few tables using LINQ and retrieve a data set. But my problem is when I group the tables, I cannot access the fields of the non grouped tables in the LINQ query. here is my sample code block. Please help
var query = from sb in db.Surfboards
join csb in db.CustomerSurfBoards on sb.SurfBoardID equals csb.SurfBoardID
join c in db.Customers on csb.CustomerID equals c.CustomerID
where c.IsActive
group new { sb,csb} by new {sb.ID, csb.ComponentId} into g
select new ReportModel()
{
ReceivedDate = g.First().Name,
Number = c.First().Number <------- this cannot be accessed
}
what I'm trying to achieve is something like this
select sb.Id, max(c.Number), cbs.Id from Surfboards as sb
inner join CustomerSurfBoards as cbs on sb.SurfBoardID = csb.SurfBoardID
inner join Customers as c on csb.CustomerID = c.CustomerID
group by sb.Id, csb.ComponentId
Try this:
var query = from sb in db.Surfboards
join csb in db.CustomerSurfBoards on sb.SurfBoardID equals csb.SurfBoardID
join c in db.Customers on csb.CustomerID equals c.CustomerID
where c.IsActive
select new {sb.id, c.number, cbs.componentid} into tmp
from t in tmp
group t by new {t.ID, t.ComponentId} into g
select new
{
g.Key.id, g.Key.componentid, number = g.Select(n=>n.number).OrderByDescending().FirstOrDefault()
}

c# linq not equals variation

I have a linq query w/ entity frameworks that works and gets the needed information, but now i am having trouble doing the opposite.
Currently it gets all the data that is needed using the joins to link tables but i need to to get some data that is not match some of the joins.
I know you can only use "equals" om linq, but i need info that is not equals
i.e. join ec in c.IsoNe on ap.idLook not equals ec.idAll
Below is the working code, but not how i need it now. any help would be appreciated...
var test = (from bil in bilats
join ap in c.Allegro on bil.idAll equals ap.idAll
join ec in c.IsoNe on ap.idLook equals ec.idAll
join cb in c.Comp on ap.idCompBuy equals cb.idComp
join cs in c.Com on ap.idCompSell equals cs.idComp
join iby in c.IsoNe on cb.idComp equals iby.idComp
join iss in c.IsoNe on cs.idComp equals isl.idComp
orderby bil.HBegin ascending
where bil.HBegin >= ec.DateTStart
where bil.HBegin < ec.DateTEnd
select new
{
Cont = ec.ContractID,
ContType = ap.idScheduleType,
Sel = isel.ISONE1,
Buy = ibel.ISONE,
HBegin = bil.HBegin,
}).ToList();
As far as I know, you'll have to create a Cartesian product and then use a where-condition to filter it. (I'm making the perhaps rash assumption that you want an inner join rather than a left join, but an inner join is what the join keyword represents.) Something like this:
var test = (from bil in bilats
join ap in c.Allegro on bil.idAll equals ap.idAll
from ec in c.IsoNe where ap.idLook != ec.idAll
join cb in c.Comp on ap.idCompBuy equals cb.idComp
join cs in c.Com on ap.idCompSell equals cs.idComp
join iby in c.IsoNe on cb.idComp equals iby.idComp
join iss in c.IsoNe on cs.idComp equals isl.idComp
orderby bil.HBegin ascending
where bil.HBegin >= ec.DateTStart
where bil.HBegin < ec.DateTEnd
select new
{
Cont = ec.ContractID,
ContType = ap.idScheduleType,
Sel = isel.ISONE1,
Buy = ibel.ISONE,
HBegin = bil.HBegin,
}).ToList();
Sounds like a join might be the wrong approach. Have a look at unions or subqueries
C# linq union question
how to do subquery in LINQ

Categories