Entity Framework inner join - c#

I have two tables something like this:
Customers:
Email
username
Products:
Username
Product
I'd like to fill a class with username, product, and email.
This is what I have so
var res = from H in db.Products
join C in db.customers on H.Username equals C.Username
where C.Username == H.Username
select H;
Results results = res.Single();
However the catch is that I'm not sure exactly how this works, can anyone break it down for me?

var res = from H in db.Products
join C in db.customers on H.Username equals C.Username
where C.Username == H.Username
select H;
Results results = res.Single();
The code above makes an inner join between C and H (the where clause is not necessary) and results in all elements given back where an appropriately connected products and customers entry exist.
The select H "just" gives back all the data from the products. As you stated that you want a mix you need to do that differently.
I myself would be using an anonymous type (or a dto object).
For an anonymous type:
select new { Username = H.Username, Product = H.Product, EMail = C.EMail}
Put together:
var res = from H in db.Products
join C in db.customers on H.Username equals C.Username
where C.Username == H.Username
select new { Username = H.Username, Product = H.Product, EMail = C.EMail}
Results results = res.Single();
For a DTO (Data Transfer Object) you would create a class with public set/get properties and use select new myClass(){....} instead of the select new {}.
DTOs are better in terms of reuse and that you have less problems with writing the names wrong that you use, ....
Just simply using select H, C sadly can't work as Linq wants to return just single objects per row (and additionally always the same datatype). Thus you need to put a container around the objects you want to return. In this case either anonymous types or DTOs.

Related

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,

Convert SQL to LINQ, with multiple joins and a predicate

I am struggling with trying to write a LINQ statement in LINQ or method syntax, based on the following SQL.
SELECT vr.*
FROM VisualReport vr
JOIN VisualReportRoleList vrl ON vr.VisualReportSK = vrl.VisualReportSK
JOIN Role r ON vrl.RoleSK = r.RoleID
JOIN UserRoleList url ON r.RoleID = url.RoleID
JOIN Users u ON url.UserID = url.UserID
WHERE u.ID = 1
I have tried many things, but without luck. I was going to post some of it here, but it just made this post really messy to read.
Can anyone here help me with this?
Join pattern works like this
Param 1. is the list to join on,
Param 2. key on the left (what your calling join on),
Param 3. key on the right (what your joining to),
Param 4. is the results selector how you want to select the results.
db.VisualReposts.Join(db.VisualRepostRoleLists,
vr => vr.VisualReportSK,
vrl => vrl.VisualReportSK
(vr, vrl) => new { vr, vrl}).Join(db.Roles,
vrj => vrj.vrl.RoleSK,
r => r.RoleID,
vrj, r => new {vr = vrj.vr,
vrl = vrj.vrl,
role = r} )
//follow the same patter for the rest of the joins.
// Also add your where clause, it might be a better idea to start
//from the users table so you can filter first
But if everything is properly foreign keyed, you don't need to do a join you can just access the ICollections. If you can or have them foreign keyed you can access them like this
var user = db.Users.Where(u => u.id == 1);
//everything should have an icollection now so you can access via
//user.UserRoleList.Roles ect or what ever you need
A simple one to one conversion. LinqPad should convert this to equivalent of your query.
var result = (from vr in VisualReport
join vrl in VisualReportRoleList on vr.VisualReportSK equals vrl.VisualReportSK
join r in Role on vrl.RoleSK equals r.RoleID
join url in UserRoleList on vrl.RoleSK equals url.RoleID
join u in Users on url.UserID equals u.UserID
where u.ID == 1
select vr).ToList();

EF Query with conditional include that uses Joins

This is a follow up to another user's question. I have 5 tables
CompanyDetail
CompanyContacts FK to CompanyDetail
CompanyContactsSecurity FK to CompanyContact
UserDetail
UserGroupMembership FK to UserDetail
How do I return all companies and include the contacts in the same query? I would like to include companies that contain zero contacts.
Companies have a 1 to many association to Contacts, however not every user is permitted to see every Contact. My goal is to get a list of every Company regardless of the count of Contacts, but include contact data.
Right now I have this working query:
var userGroupsQueryable = _entities.UserGroupMembership
.Where(ug => ug.UserID == UserID)
.Select(a => a.GroupMembership);
var contactsGroupsQueryable = _entities.CompanyContactsSecurity;//.Where(c => c.CompanyID == companyID);
/// OLD Query that shows permitted contacts
/// ... I want to "use this query inside "listOfCompany"
///
//var permittedContacts= from c in userGroupsQueryable
//join p in contactsGroupsQueryable on c equals p.GroupID
//select p;
However this is inefficient when I need to get all contacts for all companies, since I use a For..Each loop and query each company individually and update my viewmodel. Question: How do I shoehorn the permittedContacts variable above and insert that into this query:
var listOfCompany = from company in _entities.CompanyDetail.Include("CompanyContacts").Include("CompanyContactsSecurity")
where company.CompanyContacts.Any(
// Insert Query here....
// b => b.CompanyContactsSecurity.Join(/*inner*/,/*OuterKey*/,/*innerKey*/,/*ResultSelector*/)
)
select company;
My attempt at doing this resulted in:
var listOfCompany = from company in _entities.CompanyDetail.Include("CompanyContacts").Include("CompanyContactsSecurity")
where company.CompanyContacts.Any(
// This is concept only... doesn't work...
from grps in userGroupsQueryable
join p in company.CompanyContactsSecurity on grps equals p.GroupID
select p
)
select company;
Perhaps something like this.
var q = from company in _entities.CompanyDetail
where
(from c in userGroupsQueryable
join p in contactsGroupsQueryable on c equals p.GroupID
where company.CompanyContacts.Any(cc => cc.pkCompanyContact == p.fkCompanyContact)
select p
).Any()
select new
{
Company = company,
Contacts = company.CompanyContacts
};
The following code queries all companies, and appends only the contacts the user is permitted to see. I don't know how efficient this is, or if there is a way to make it faster, but it works.
var userGroupsQueryable = _entities.UserGroupMembership.Where(ug => ug.UserID == UserID)
.Select(a => a.GroupMembership);
var  contactsGroupsQueryable = _entities.CompanyContactsSecurity;
var listOfCompanies =
from company in _entities.CompanyDetail
select new
{
Company = company,
Contacts = (from c in userGroupsQueryable
join p in contactsGroupsQueryable on c equals p.GroupID
where company.CompanyContacts.Any(cc => cc.CompanyID == p.CompanyID)
select p.CompanyContacts)
};

LinQ query with multiple tables and extracting data

I'm doing a query to inner join 4 tables and I have to extract data and convert into string and place it in an array for it.
var query = from a in context.as
join b in context.bs on a.prikey equals b.forkey
join c in context.cs on b.prikey equals c.forkey
join d in context.ds on c.prikey equals d.forkey
where b.gender == gender
where c.age == age
select new
{
a.Name,
a.Age,
b.Gender,
};
string[] results = new string[] {}
return results;
Normally, if a single table is involved
a as = plural of table a
as t = query.First()
string[] results = new string[] {t.Name, t.Age, t.Gender}
return results;
I'm missing a step to extract the data.
It depends what exactly you want to do with the data. Your code won't actually compile at the moment as it's trying to create an anonymous type with multiple properties all called "arg" but I'm assuming you've really got a more sensible query.
Ultimately, the fact that you're using multiple tables is irrelevant here - you're only getting a single result element at a time: the fact that each result element contains data from multiple tables is neither here nor there in terms of how you access it.
Now I've just noticed that you say you want to "extract data and convert into string". If possible, you should express that in your query. You may be able to do that at the database, or you may need to force the final part of the execution to execute locally, like this:
// Not executed yet!
var dbQuery = from a in context.a
join b in context.bs on a.prikey equals b.forkey
join c in context.cs on b.prikey equals c.forkey
join d in context.ds on c.prikey equals d.forkey
where ...
select { a.Age, b.Name, c.Salary, d.Location };
// This still won't talk to the database!
var finalQuery = dbQuery.AsEnumerable()
.Select(x => string.format("Age: {0}; Name: {1}; " +
"Salary: {2}; Location: {3}",
x.Age, x.Name, x.Salary,
x.Location));
// This will finally execute the query
string[] results = finalQuery.ToArray();
Now you don't have to do it like this - but it's probably the best approach, at least with the amount of information you've given us. If you can tell us more about how you're trying to combine the data from the multiple tables, we may be able to help you more.
EDIT: Okay, now you've given us a bit more information, I suspect you want:
var query = from a in context.a
join b in context.bs on a.prikey equals b.forkey
join c in context.cs on b.prikey equals c.forkey
join d in context.ds on c.prikey equals d.forkey
where ...
select new string[] { a.arg, b.arg, c.arg, d.arg };
string[] results = query.First();
I haven't tried creating arrays in LINQ to SQL... that may work, or you may need to go via an anonymous type and AsEnumerable as per the earlier part of my answer.
You should also think about what you want to happen if there are no results, or multiple results.
EDIT: Having seen the edited question, you really can treat multiple tables the same way as a single table. You'd use exactly the same code for handling the result, once it's been projected into an anonymous type:
var query = from a in context.as
join b in context.bs on a.prikey equals b.forkey
join c in context.cs on b.prikey equals c.forkey
join d in context.ds on c.prikey equals d.forkey
where ...
select new { a.Name, a.Age, b.Gender };
var result = query.First();
// Call ToString appropriately on each property, of course
string[] array = new string[] { result.Name, result.Age, result.Gender };
var query = from a in context.a
join b in context.bs on a.prikey equals b.forkey
join c in context.cs on b.prikey equals c.forkey
join d in context.ds on c.prikey equals d.forkey
where a.arg == arg
where b.arg == arg
where c.arg == arg
select new
{
allStrings = a.arg +
a.arg +
b.arg +
c.arg +
d.arg
};
string[] results = query.ToArray();

Categories