joining a table with more than one field in same table - entity-framework

I try to create a join query in Linq. I want to join a table more than one field with same
table. Please see my code below.
var roles = (from ords in _orderRepository.Table
join customers in _customerRepository.Table on ords.CustomerId equals customers.Id
join ordprvrnts in _orderProductVariantRepository.Table on ords.Id equals ordprvrnts.OrderId
join prdvrnts in _productVariantRepository .Table on ordprvrnts.ProductVariantId equals prdvrnts.Id
**join cstevntrle in _customerEventRoleRepository.Table on
new{ customers.Id equals cstevntrle.CustomerId } &&
new { cstevntrle.EventId == model.Event}**
orderby customers.Email ascending
select new CustomerEventRolesModel
{
Customer = customers.Email,
CUstomerId =customers.Id
});
I try to filter customerEventRoleRepository.Table with CustomerId and EventId
how can i do this in this join query.
Please Help.

you have boolean comparisons in your anonymous type definitions...
change your on clause to the following:
join cstevntrle in _customerEventRoleRepository.Table on
new { CustomerId = customers.Id, EventId = model.Event.EventId } equals
new { CustomerId = cstevntrle.CustomerId, EventId = cstevntrle.EventId }
I don't see "model" defined anywhere, so I'm not sure this is going to work, but it should be enough to demonstrate how joins based on multiple fields works - each anonymous class contains the fields from one "side" of the join.

Related

LINQ - Conditional Join

I have a condition where joining table have a condition. Let's say I have a table called Mapper Student Teacher where Mapper table have a column named AcNoId which contains a id from both table Student and Teacher. The table structure is
Mapper
Student
Teacher
TestOption is a enum and is defined as a
public enum TestOption
{
Teacher = 1,
Student = 2
}
Now I have a condition where if TestOption is a type of Student it should perform a join with Student table and if is a type of Teacher it should perform a join with Teacher table
This is how I have tried so far
(from m in _context.Mapper
where m.TestOption == TestOption.Student
join s in _context.Student
on m.AcNoId equals s.Id into tempStudent
from st in tempStudent.DefaultIfEmpty()
where m.TestOption == TestOption.Teacher
join t in _context.Teacher
on m.AcNoId equals t.Id into tempTeacher
from ta in tempTeacher.DefaultIfEmpty()
select new
{
Type = m.TestOption.ToString(),
Student = st.StudentName ?? string.Empty,
Teacher = ta.TeacherName ?? string.Empty
}).ToList();
Instead of conditional join this query perform a following query on SQL Profiler
exec sp_executesql N'SELECT [m].[TestOption], COALESCE([s].[StudentName], #__Empty_0) AS [Student], COALESCE([t].[TeacherName], #__Empty_1) AS [Teacher]
FROM [Mapper] AS [m]
LEFT JOIN [Student] AS [s] ON [m].[AcNoId] = [s].[Id]
LEFT JOIN [Teacher] AS [t] ON [m].[AcNoId] = [t].[Id]
WHERE ([m].[TestOption] = 2) AND ([m].[TestOption] = 1)',N'#__Empty_0 nvarchar(4000),#__Empty_1 nvarchar(4000)',#__Empty_0=N'',#__Empty_1=N''
How can I do this????
You can use the below code, with no need to use join or where statements on _context.Mapper:
(from m in _context.Mapper
select new
{
Type = m.TestOption.ToString(),
Student = _context.Student
.FirstOrDefault(s =>
m.TestOption == TestOption.Student &&
s.Id == m.AcNoId) ?? string.Empty,
Teacher = _context.Teacher
.FirstOrDefault(t =>
m.TestOption == TestOption.Teacher &&
t.Id == m.AcNoId) ?? string.Empty,
})
.ToList();

Compare two arrays in LINQ query

I want to write LINQ query to compare two arrays. I want the query to be translated to the following query:
SELECT id, name
FROM persons
WHERE '{"dance", "acting", "games"}' && (hobbies);
That condition work in that way:
'{"dance"}' && '{"dance", "acting", "games"}'; -- true
'{"dance","singins"}' && '{"dance", "acting", "games"}'; -- true
'{"singins"}' && '{"dance", "acting", "games"}'; -- false
I wrote this query:
List<string> arr = new List<string>(){ "dance", "acting", "games" };
var query = (from p in _context.Persons
where arr.Any(kw => p.hobbies.Contains(kw))
select new
{
id = p.id,
name = p.name
}).ToList();
The translated query is:
SELECT p."id" AS id, p."name" AS name
FROM dataBase."Persons" AS p
It can understand that the filter performs in the server. so the query brings all the data from DB and filtered on the server. This causes to performance problems and not pass Load-Testing.
I need a query that will not only do the job but will also be translated to the above query with '&&'.
Is there any way in LINQ to execute this query?
Thanks
If your database looks similar like I am predicting this could be a solution. Some more code though but I think this should be executed as a SQL IN statement:
List<string> arr = new List<string>(){ "dance", "acting", "games" };
var matches = from hobby_person in _context.Hobbies_Persons
join person in _context.Persons on person.Id equals hobby_person.PersonId
join hobby in _context.Hobbies on hobby.Id equals hobby_person.HobbyId
where arr.Contains(hobby.Name)
select new
{
id = p.id,
name = p.name
}).ToList();

when inner join in linq how can i select same column without using model class

Actually ,I want to extract generic data from EF table without using models but unfortunately two columns with same name from different database crashed...
Here is the query
var query = (from jbct in entities.Table1.AsEnumerable()
join p in entities.Table2.AsEnumerable() on jbct.perid equals p.id
select new
{
jbct.id,
p.id
}).ToList();
try use a dynamic name
var query = (from jbct in entities.Table1.AsEnumerable()
join p in entities.Table2.AsEnumerable() on jbct.perid equals p.id
select new
{
Id1 = jbct.id,
Id2 = p.id
}).ToList();
Now I've found now my solution to usie dictionary class
Dictionary with object as value
var query = (from jbct in entities.Table1.AsEnumerable() join p in entities.Table2.AsEnumerable() on jbct.perid equals p.id select new Dictionary<String, Object>
{
{"jbct_id", jbct.id},
{"p_id", p.id}}
).ToList();
Thanks

Make group by in outter join LINQ to entity

I use Entity Framework-6.
I have this code(outter join, LINQ to entity):
var inspectionSitesConjection = (from st in sites
join ir in inspectionReview on st.Id equals ir.SiteId into g
from subsite in g.DefaultIfEmpty()
select new GeneralReportViewModel
{
siteName = subsite.Site.Name,
address = subsite.Site.Description,
inspectionDate = subsite.DateReview,
siteType = subsite.Site.SiteType.Description,
frequency = subsite.InspectionFrequency.Name,
status = subsite.IsNormal,
}).AsNoTracking();
I need to make group by siteName and frequency.
Is it pussable to make group by inside LINQ above?
Here is a starting point:
var grouped = inspectionSitesConjection
.GroupBy(item => new { item.siteName, item.frequency });
But note that the result (as you may see in Queryable.GroupBy documentation) is no more IQueryable<GeneralReportViewModel> but IQueryable<IGrouping<Key, GeneralReportViewModel>> where Key is anonymous type having siteName and frequency properties.
I'm providing this just because you specifically asked. It's not quite clear what are you trying to achieve with that query. Also, once you decided to use explicit join, then use the joined table instead of navigation property, and take into account that subsite can be null due to outer join.
from st in sites
join ir in inspectionReview on st.Id equals ir.SiteId into g
from subsite in g.DefaultIfEmpty()
select new GeneralReportViewModel
{
siteName = st.Name,
address = st.Description,
siteType = st.SiteType.Description,
inspectionDate = subsite.DateReview, // problem if subsite == null
frequency = subsite.InspectionFrequency.Name, // problem if subsite == null
status = subsite.IsNormal, // problem if subsite == null
})

EF Left joining a table on two properties combined with a case statement

I'm trying to write a query for a database that will left join a table to a look up table and the results will be returned based on a case statement.
In normal SQL the query would look like this:
SELECT chis_id, chis_detail, cilt.mhcatID, cilt.mhtID, 'TheFileName' =
CASE
WHEN cilt.mhcatID IS NOT NULL AND cilt.mhtID IS NOT NULL THEN chis_linked_filename
END
FROM chis
LEFT JOIN cilt on cilt.mhcatID = chis.mhcat_id AND cilt.mhtID = chis.mht_id
WHERE cch_id = 50
chis is the table being queried, cilt is a look-up table and does not contain any foreign key relationships to chis as a result (chis has existing FK's to mht and mhcat tables by the mhtID and mhcatID respectively).
The query will be used to return a list of history updates for a record. If the join to the cilt lookup table is successful this means that the caller of the query will have permission to view the filename of any associated files for the history updates.
Whilst during my research I've found various posts on here relating on how to do case statements and left joins in Linq to Entity queries, I've not been able to work out how to join on two different fields. Is this possible?
You need to join on an anonymous type with matching field names like so:
var query = from x in context.Table1
join y in context.Table2
on new { x.Field1, x.Field2 } equals new { y.Field1, y.Field2 }
select {...};
A full working example using the an extra from instead of a join would look something like this:
var query = from chis in context.Chis
from clit in context.Clit
.Where(x => x.mhcatID = chis.mhcat_id)
.Where(x => x.mhtID = chis.mht_id)
.DefaultIfEmpty()
select new
{
chis.id,
chis.detail,
cilt.mhcatID,
cilt.mhtID,
TheFileName = (cilt.mhcatID != null && cilt.mhtID != null) ? chis.linked_filename : null
};
Based on what Aducci suggested, I used a group join and DefaultIsEmpty() to get the results I wanted. For some reason, I couldn't get DefaultIfEmpty() didn't work correctly on its own and the resulting SQL employed an inner join instead of a left.
Here's the final code I used to get the left join working:
var query = (from chis in context.chis
join cilt in context.cilts on new { MHT = chis.mht_id, MHTCAT = chis.mhcat_id } equals new { MHT = cilt.mhtID, MHTCAT = cilt.mhcatID } into tempCilts
from tempCilt in tempCilts.DefaultIfEmpty()
where chis.cch_id == 50
select new {
chisID = chis.chis_id,
detail = chis.chis_detail,
filename = chis.chis_linked_filename,
TheFileName = (tempCilt.mhcatID != null && tempCilt.mhtID != null ? chis.chis_linked_filename : null),
mhtID = chis.mht_id,
mhtcatID = chis.mhcat_id
}).ToList();