Entity Framework 6 - Outer Joins and Method Syntax Queries - c#

I'm trying to re-write the following SQL LEFT OUTER JOIN query using Entity Framework 6:
select tblA.*, tblB.*
from dbo.TableA tblA left outer join dbo.TableB tblB on
tblA.Student_id=tblB.StudentId and tblA.other_id=tblB.OtherId
where tblB.Id is null
Here's my current C# code:
using (var db = EFClass.CreateNewInstance())
{
var results = db.TableA.GroupJoin(
db.TableB,
tblA => new { StudentId = tblA.Student_id, OtherId = tblA.other_id },
tblB => new { tblB.StudentId, tblB.OtherId },
(tblA, tblB) => new { TableAData = tblA, TableBData = tblB }
)
.Where(x => x.TableBData.Id == null)
.AsNoTracking()
.ToList();
return results;
}
And here's the following compiler error I'm getting:
The type arguments cannot be inferred from the usage. Try specifying
the type arguments explicitly.
In a nutshell: I need to OUTER JOIN the two DbSet objects made available via Entity Framework, using more than one column in the join.
I'm also fairly certain this won't do a LEFT OUTER JOIN properly, even if I wasn't getting a compiler error; I suspect I need to involve the DefaultIfEmpty() method somehow, somewhere. Bonus points if you can help me out with that, too.
UPDATE #1: It works if I use a strong type in the join... is it simply unable to handle anonymous types, or am I doing something wrong?
public class StudentOther
{
public int StudentId { get; set; }
public int OtherId { get; set; }
}
using (var db = EFClass.CreateNewInstance())
{
var results = db.TableA.GroupJoin(
db.TableB,
tblA => new StudentOther { StudentId = tblA.Student_id, OtherId = tblA.other_id },
tblB => new StudentOther { StudentId = tblB.StudentId, OtherId = tblB.OtherId },
(tblA, tblB) => new { TableAData = tblA, TableBData = tblB }
)
.Where(x => x.TableBData.Id == null)
.AsNoTracking()
.ToList();
return results;
}

can you please try this solution? I'm not sure about the result :(
(from tblA in dbo.TableA
join tblB in dbo.TableB on new { tblA.Student_id, tblA.other_id } equals new { blB.StudentId, tblB.OtherId }
into tblBJoined
from tblBResult in tblBJoined.DefaultIfEmpty()
where tblBResult.Id == null
select new {
TableAData = tblA,
TableBData = tblB
}).ToList();

Related

how to apply join or innerquery to connect two table

Here MyChildTable contains only id and the parent table contains id + name.
I have written a query to fetch the existing data from the table
await _dbContext.MyChildTable
.Where(c => c.CustomerId == **(select customerid from tableParent where customername= reqcustomername)**
Here i want to match customerId with the matching customer id from the second table ie tableParent.How to replace the query in to linq to get the proper record.select customerid from tableParent where customername= reqcustomername i want to replace this selection
I don't understand what you mean
so my maybe answer error
LINQ
using (entity entityData = new entity())
{
var checkqry2 = from T1 in entityData.MyChildTable.AsNoTracking()
join T2 in entityData.tableParent on
T1.CustomerId equals T2.customerid
where T1.customerid == "ID" && T2.customername == reqcustomername
group new { T2.customerid, T2.customername } by new { T1.customerid, T1.customername } into c
orderby c.Key.customerid
select new { customername=c.Key.customername,
customerid=c.Key.customerid,
};
}
you can try entity lambda
entity lambda
using (entity entityData = new entity())
{
var query1 = entityData.MyChildTable
.Join(entityData.tableParent , o => o.CustomerId , p => p.CustomerId , (o, p) => new
{
o.CustomerId,
p.customername,
}).Where(o => o.CustomerId == "123" && o.customername == "name").ToList();
}
Here I want to match customerId with the matching customer id from the
second table ie tableParent.How to replace the query in to linq to get
the proper record.select customerid from tableParent where
customername= reqcustomername i want to replace this selection
Well, lot of way around to handle this kind of scenario. Most easy and convenient way you could consider by using linq join or linq Enumerable which you can implement as following:
Sample Data:
var childList = new List<ChildTable>()
{
new ChildTable(){ Id =101,ChildName = "Child-A",CustomerId = 202},
new ChildTable(){ Id =102,ChildName = "Child-B",CustomerId = 203},
new ChildTable(){ Id =103,ChildName = "Child-C",CustomerId = 202},
new ChildTable(){ Id =104,ChildName = "Child-D",CustomerId = 204},
};
var parentList = new List<ParentTable>()
{
new ParentTable(){ Id =301,ParentName = "Parent-A",CustomerId = 202},
new ParentTable(){ Id =302,ParentName = "Parent-B",CustomerId = 202},
new ParentTable(){ Id =303,ParentName = "Parent-C",CustomerId = 203},
new ParentTable(){ Id =304,ParentName = "Parent-D",CustomerId = 205},
};
Linq Query:
Way One:
var findMatchedByCustId = from child in childList
where (from parent in parentList select parent.CustomerId)
.Contains(child.CustomerId)
select child;
Way Two:
var usingLinqJoin = (from parent in parentList
join child in childList on parent.CustomerId equals child.CustomerId
select parent).ToList().Distinct();
Output:
Note: If you need more information you could check our official document for Linq join and Linq Projction here.

LINQ query doesn't return the single value

I have this query and I want to return a single value which is the I.Id and I have a parameter which is filled with an Id that is sent from a Controller to the Dao(Where the Linq query is nested).
The problem is, that this query isn't just returning a value, is returning every fields in the table that this query produces and I just want the Id.
This is the query:
public InscriptionDetail GetInscriptionIdByPersonId(int id)
{
using (var db = new HIQTrainingEntities())
{
var inscription =
from i in db.Inscriptions
join c in db.Certifications on i.PersonId equals c.PersonId
where i.PersonId == id
select new InscriptionDetail
{
Id = i.Id,
};
return inscription.FirstOrDefault();
}
}
Can someone help me with this query ?
What's wrong ?
Your return type is of InscriptionDetail. If it is only the int id you need to return, why not change to the following?
public int GetInscriptionIdByPersonId(int personId)
{
using (var db = new HIQTrainingEntities())
{
var inscription =
from i in db.Inscriptions
join c in db.Certifications on i.PersonId equals c.PersonId
where i.PersonId == personId
select i.Id;
return inscription.FirstOrDefault();
}
}

How to sort in LINQ If Join other database

Sort in LINQ
I have 2 database CustomerEntities and BillEntities
I want to get CustomerName from CustomerEntities and sort it but it have no data and I want .ToList() just once time because it slow if used many .ToList()
using (var db1 = new CustomerEntities())
{ using (var db2 = new BillEntities())
{
var CustomerData = db1.Customer.Select(s=> new{s.CustomerCode,s.CustomerName}).ToList();
var BillData = (from t1 in db2.Bill
select new {
BillCode = t1.Billcode,
CustomerCode = t1.Customer,
CustomerName = ""; //have no data
});
}
if(sorting.status==true)
{
BillData= BillData.OrderBy(o=>o.CustomerName); //can't sort because CustomerName have no data
}
var data = BillData .Skip(sorting.start).Take(sorting.length).ToList(); // I want .ToList() just once time because it slow if used many .ToList()
foreach (var b in data)
{
var Customer = CustomerData.FirstOrDefault(f => f.CustomerCode==b.CustomerCode );
if(CustomerName>!=null)
{
r.CustomerName = Customer.CustomerName; //loop add data CustomerName
}
}
}
I have no idea to do it. Help me please
I'm not sure if I understand your code but what about this:
var BillData = (from t1 in db2.Bill
select new {
BillCode = t1.Billcode,
CustomerCode = t1.Customer,
CustomerName = db1.Customer.FirstOrDefault(c => c.CustormerCode == t1.Customer)?.CustomerName
});
Then you have objects in BillData that holds the CustomerName and you can order by that:
BillData.OrderBy(bd => bd.CustomerName);
If you just want to get CustomerName from your customer Db and sort it, this is what i would have used. I used orderByDescending but you can use OrderBy aswell.
public List<Customer> getLogsByCustomerName(string customername)
{
using (var dbentites = new CustomerEntities())
{
var result = (from res in dbentites.Customer.OrderByDescending(_ => _.CustomerName)
where res.CustomerName == customername
select res).ToList();
return result.ToList();
}
}

.Include() still queries database after a ToList()

I have the following View defined in my Context class, Entity Framework: I have added .Include() here, with the hopes that this will eliminate calls to database later.
public IQueryable<GeneralReportModel> vwGeneralReportItems
{
get
{
return from p in this.Patients.AsNoTracking().Include(p => p.Age) //Multiple includes added to include all properties on model
join fac in this.Facilities.AsNoTracking() on p.FacilityID equals fac.ID into fJoin
from f in fJoin.DefaultIfEmpty()
join userFac in this.UserFacilities.AsNoTracking() on p.FacilityID equals userFac.FacilityID into ufJoin
from uf in ufJoin.DefaultIfEmpty()
select new GeneralReportModel()
{
Patient = p,
//ReportIndex = ri,
Facility = f,
UserFacility = uf
};
}
}
I also have this function, which does some filtering on my select from the View:
private IQueryable<GeneralReportModel> generalReportQuery(ApplicationTypes.ReportParameterObject repParam)
{
var reportQuery = ReportHelper.GeneralReport_Source(this.DbContext, repParam, false);
reportQuery = ReportHelper.GeneralReport_FilterCriteria(this.DbContext, reportQuery, repParam);
// Lab confirmed - Extra Pulmonary
reportQuery = reportQuery.Where(rq =>
rq.Patient.TypeOfResistantTBConfirmation.Value == ApplicationTypes.ResistantTBConfirmationTypes.LABCONFIRMED.ToString() &&
rq.Patient.SiteOfDiseaseID != repParam.DatabaseSettingObject.SiteOfDiseaseID_ExtraPulmonary &&
rq.Patient.PatientCategoryID != ApplicationGlobal.GLBDATABASESETTINGOBJECT.PatientCategoryID_TransferIn);
return reportQuery;
}
The code below
var reportQueryMdr = reportQuery.Where(rq =>
rq.Patient.TypeOfResistantTB.Value == ApplicationTypes.ResistantTBTypes.MDR.ToString());
var list = reportQueryMdr.ToList();
foreach (var obj in list)
{
obj.ReportIndex = obj.Patient.getRecalculatedReportIndexFields(ApplicationGlobal.GLBDATABASESETTINGOBJECT);
}
reportQueryMdr = list.AsQueryable();
Still calls the Database for each iteration made over the list. How can I make this list entirely reside in memory, with all the Patient properties.

LINQ Conditionally Add Join

I have a LINQ query where I'm trying to return data from 2 tables, but the tables that I join are conditional.
This is what I'd like to do:
if (teamType == "A"){
var query = from foo in context.People
join foo2 in context.PeopleExtendedInfoA
select foo;
}
else {
var query = from foo in context.People
join foo2 in context.PeopleExtendedInfoB
select foo;
}
Then later on I'm filtering the query down even further. I obviously can't set it up this way because I won't be able to access "query" outside the if block, but it shows what I'm trying to do. This is an example of what I'm trying to do later on with the query:
if (state != null)
{
query = query.Where(p => p.State == state);
}
if (query != null) {
var queryFinal = from foo in query
select new PeopleGrid()
{
Name = foo.Name,
Address = foo.Address,
Hobby = foo2.Hobby
}
}
What I'm trying to return is all the data from table foo and then one field from the joined table, but depending on the logic, the joined table will differ. Both PeopleExtendedInfoA and PeopleExtendedInfoB both have the columb 'Hobby', but I have no way to access 'Hobby' from the joined table and that's the only field I need from the joined table.
How would I go about doing this?
Does PeopleExtendedInfoA and PeopleExtendedInfoB inherits from the same base class? You could create a IQueryable<BaseClass> and let the linq provider solve it for you when you add the join. For sample:
IQueryable<BasePeople> basePeople;
if (teamType == "A")
basePeople = context.PeopleExtendedInfoA;
else
basePeople = context.PeopleExtendedInfoB;
var query = from foo in context.People
join foo2 in basePeople on foo.Id equals foo2.PeopleId
select new PeopleGrid()
{
Name = foo.Name,
Address = foo.Address,
Hobby = foo2.Hobby
};
try like this:
var queryFinal = from foo in query
where foo.State == state !=null ? state : foo.State
select new PeopleGrid()
{
Name = foo.Name,
Address = foo.Address,
Hobby = foo2.Hobby
}
You can query into an intermediate type that holds the relevant fields, or if the query is simple enough you can use anonymous types as seen below. The important part is that the Join calls both have the same return types ({ p.Name, a.Hobby } and { p.Name, b.Hobby } will both be the same anon type).
var baseQuery = context.People;
var joined = type == "A" ?
baseQuery.Join(PeopleExtendedInfoA,
p => p.Id,
a => a.PeopleId,
(p, a) => new { p, a.Hobby }) :
baseQuery.Join(PeopleExtendedInfoB,
p => p.Id,
b => b.PeopleId,
(p, b) => new { p, b.Hobby });
var result = joined.Select(x => new
{
x.p.Name,
x.p.Address,
// etc.
x.Hobby
};
I figured it out. Thanks everyone for all the replies, it got my brain working again and gave me some new ideas (even though I didn't directly take any of them) I realize I needed to do the join at the very end instead of the beginning that way I don't have to deal with filtering on different types. This is what I did:
var query = from foo in context.People
select foo;
if (state != null)
{
query = query.Where(p => p.State == state);
}
if (query != null) {
if (teamType == "A")
{
var queryFinal = from foo in query
join foo2 in context.PeopleExtendedInfoA
select new PeopleGrid()
{
Name = foo.Name,
Address = foo.Address,
Hobby = foo2.Hobby
}
}
else
{
var queryFinal = from foo in query
join foo2 in context.PeopleExtendedInfoB
select new PeopleGrid()
{
Name = foo.Name,
Address = foo.Address,
Hobby = foo2.Hobby
}
}
}

Categories

Resources