LINQ Query for particular situation - c#

Lets say that I have following tables:
Student(id(pk), name)
Class(id(pk), name)
StudentClass(id(pk), studentId(fk), classId(fk))
Imagine as follows:
Student table contains:
(1,"John"), (2, "Mike"), (3,"Josh")
Class table contains:
(1,"Geography"), (2, "Math")
StudentClass table contains:
(`1, 1, 1),(2,2,2),(3,3,2)
Lets now assume that I have a StudentClassDTO class which contains
List<string> StudentNames
string ClassName
How can I by using using LINQ query get data into StudentClassDTO? Any help appreciated.
var data = from sc in context.GetStudentClasses
join s in context.GetStudents on sc.StudentId equals s.Id
join c in context.GetClass on sc.ClassId equals c.Id
select new StudentClassDTO
{
}
so it gets name and classname 3 seperate ones but I need if their classes are same it should have to combine them where it will be just one classname and 2 different students. So it should be like {john, Geography} and {[Mike, Josh], Math}
Solution
from c in classes
join sc in studentClasses on c.Id equals sc.ClassId
join s in student on sc.StudentId equals s.StudentId
group s by new {c.Name} into g
select new StudentClassDTO
{
ClassName = g.Key.Name,
StudentNames = g.Select(a=>a.Name).ToList()
};

I use code like this all the time to accomplish what you're trying to do (untested and using the C# 7.3 syntax).
var xs =
from s in ctx.students
join cs in ctx.student_classes on cs.student_id equals s.student_id
join c in ctx.classes on c.class_id equals cs.class_id
select new
{
s, c
}
var memo = new Dictionary<int, StudentClassDTO>(); //the key is class_id
foreach(var x in xs)
{
if(!memo.Contains(x.c.class_id, out var #class))
memo.Add(x.c.class_id, #class = new StudentClassDTO(x.c.class_name));
#class.Accept(s.student_name);
}
sealed class StudentClassDTO
{
readonly List<string> student_names;
public string ClassName { get; }
public IEnumerable<string> StudentNames => student_names;
public(string class_name)
{
ClassName = class_name;
}
public void Accept(string name) => student_names.Add(name);
}

Using the LINQ group join operator, you can get a collection of matching student classes, however your query needs to start from the Class table since you want one StudentClassDTO per class. Unfortunately you have to nest the join from student classes to students (an EF navigation property may do better) so this may generate multiple queries.
var data = from c in context.GetClass
join sc in context.GetStudentClasses on c.Id equals sc.ClassId into scj
select new StudentClassDTO {
ClassName = c.Name,
StudentNames = (from sc in scj
join s in context.GetStudents on sc.StudentId equals s.Id
select s.Name).ToList()
};

Related

EF-Core LINQ JOIN with include()

Question: Is the above possible in EF-Core 1.1? I'm trying the following but VS2015 complaining on line Select new TestViewModel{...} with the error: name Select does not exist in the current context. If the above is not possible what's a workaround while sill using include(...)? Note: Customers is joined to Addresses and Orders table
var qry = from c in _context.Customers.Include(t => t.Addresses).Where(c => c.Region== "NW").OrderBy(c => c.Name)
join ord in _context.Orders on c.CustomerID equals ord.CustomerID
Select new TestViewModel
{
CustName = c.Name,
CustRegion = c.Region,
OrderType = ord.Type,
....
};
select is a keyword, and keywords are case-sensitive. Just like you cannot declare class Public Static - you cannot use Select.

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}

Elegant way to create List<>

I am using this LINQ to Entity:
var t1 = (from cn in contracts
join cl in client on cn.Id equals cl.Id
join so in siteObject on cn.Id equals so.ContractId
select new
{
siteObjId = so.Id,
clientId = cl.Id,
}).ToList();
t1 have this list:
Is there any elegant way using (for example LINQ) to create from the list above (t1), new list like that:
You could group by statement the items. For each item of result, you could concat the result group using string.Join(separator, collection) to get a result like 1,2,3. But, first, given you are using Linq To Entities, first, try to execute a simple query grouping values. For sample:
var groupResult = (from cn in contracts
join cl in client on cn.Id equals cl.Id
join so in siteObject on cn.Id equals so.ContractId
group cl by cl.Id into g
select new {
ClientId = g.Key,
Result = g
}).ToList();
And use Linq To Objects with the groupResult list, to join the values into a string, for sample:
var t1= (from item in groupResult
select new {
clientId = item.ClientId,
siteObjId = string.Join(",", item.ToList()),
});
You want the group by operator:
(from x in t1
group x b x.ClientId into g
select new
{
ClientId = g.Key,
ModelIds = g.ToList()
}).ToList()

LinqToSQL join what type to use as return on List

I got the join below, what type/class would I return to keep all the properties? This is the NorthWind database, which I think most guys are familiar with.
var q =
from a in db.GetTable<Order_Detail>()
join b in db.GetTable<Product>() on a.ProductID equals b.ProductID
select a;
You have two choices, you can select it as an anonymous type, like this
var q =
from a in db.GetTable<Order_Detail>()
join b in db.GetTable<Product>() on a.ProductID equals b.ProductID
select new { a, b };
This will give you an object q with a and b on it, so for example you can do:
q.a.SomeOrderInformation
q.b.SomeProductInformation
Or you can select it into a class.
Create a new class with the fields you want:
public class MyNewClass {
public string MyOrderProperty {get; set;}
public string MyProductProperty {get; set;}
}
Then populate it with:
var q =
from a in db.GetTable<Order_Detail>()
join b in db.GetTable<Product>() on a.ProductID equals b.ProductID
select new MyNewClass { MyProductProperty = b.ProductId, MyOrderProperty = a.OrderName };
Change the fields/class name to fit I just made them up as I don't have access to northwind.
What you want to do is create a new anonymous type to return both values:
var q =
from a in db.GetTable<Order_Detail>()
join b in db.GetTable<Product>() on a.ProductID equals b.ProductID
select new
{
Order = a,
Product = b
};
Note that if you have your foreign keys set up properly, you shouldn't need to do an explicit join at all. You should be able to say Order_Detail.Products to get the Products within an Order_Detail.

SQL Query selecting where there are more than 3 distinct

I am having problems with a SQL query, i need a list of consumers having purchased at least 3 different products whose suppliers are from a certain city (Lets say new york).
Tabels Columns:
Tb_Consumer..........Con_ID(PK), Name, City
Tb_Supplier.............Supp_ID(PK), Name, City
Tb_Transactions.....Tran_ID(PK), Supp_ID(FK), Con_ID(FK), PROD_ID(FK)
Tb_Products............Prod(ID(PK), Name
What i have so far:
var query8Result = (from c in context.Tb_Consumer
join t in context.Tb_Transactions on c.Con_ID equals t.Con_ID
join s in context.Tb_Supplier on t.Supp_ID equals s.Supp_ID
join p in context.Tb_Product on t.Prod_ID equals p.Prod_ID
where s.City == "New York"
select new { Name = c.Name }).Distinct();
I think you need a few Group-by's
var query8Result = (from c in context.Tb_Consumer
join t in context.Tb_Transactions on c.Con_ID equals t.Con_ID
join s in context.Tb_Supplier on t.Supp_ID equals s.Supp_ID
join p in context.Tb_Product on t.Prod_ID equals p.Prod_ID
where s.City == "New York"
group c by new { c.Name, t.Prod_ID } into customerProducts
group customerProducts by new { customerProducts.Key.Name } into customers
where customers.Count() > 3
select g.Key);
Sorry if this isn't 100% correct - It's a little hard to test this...

Categories