Complicated Join in Entity Framework - linq

I have 3 tables in a database (picture below). I am trying to join the tables so I can get all the related information from all the tables. I am starting at DAT_Demo and I have been able to get all the records from DAT_Demo and ARC_Records, but I cannot figure out how to also pull in all the DAT_OrderDoctors records associated with ARC_Records. I have the following code that pulls the records I want but DAT_OrderDoctors is not available. How can i do this?
Code so far:
IQueryable<DAT_Demo> query = _localContext.DAT_Demo
.Include("ARC_Records")
.Include("ARC_Immuno")
.OrderBy(d => d.LastName)
.Where(d => SqlFunctions.PatIndex(txtSearch.Text + "%", d.FirstName + " " + d.LastName) > 0)
.Take(100);
demo = query.ToList();

I think you are after a second level include
.Include("ARC_Records.DAT_OrderDoctor")
or
.Include(d=>d.ARC_Records.Secect(a=>a.DAT_OrderDoctor))

Related

Dynamic Linq core

Hi I am using a Jqwidgets Grid to display my data. It has a build in possibility to use filters but if you filter your records on the server side you have to build your own query. As I am working with Linq I thought to use the Dynamic Linq Library for Asp net core. Problem is there are not many examples or explanations how to do this. But I am busy for days now and not getting very far.The way I am setup; I have a normal Linq query:
var Mut = from M in _DB.Mutations
join S in _DB.Shifts on M.ShiftId equals S.ShiftId
join U in _DB.RoosterUsers on M.UserId equals U.RoosterUserId
join D in deps on M.UserId equals D.UserId
join DD in _DB.Departements on D.DepartementID equals DD.DepartementId
select new MutationModel
{
MutId=M.MutationId,
Naam=U.FirstName + " " + U.LastName,
UserId=M.UserId,
Departement= DD.DepartementName,
MutationType = S.publicName,
MutationGroup = S.ShiftType.ToString(),
DateTot =M.DateTill,
TijdVan=M.DateStartOn,
TijdTot=M.DateTill,
Status=CreateStatus(M.Tentative, M.ApprovedOn, M.Processed, M.CancelRefId, M.Deleted)
};
This query is running OK and gives me all the data I need for the Grid.
Then for the filter I would like to add a dynamic Linq Query using the System.Linq.Dynamic.Core library
But this is as far as I get things working until now:
var outQuery = Mut.Where("Status = #0 and UserId = #1", "Nieuw", "KLM22940").Select("Status");
My questions now :
1. In the where clause If I make the fieldname variable I get an error. how to do this??
2. In the Select Clause, how to add multiple Columns? (actually I just like to output all columns.)
Best would be to see an example. has somebody used Dynamic Linq to build a dynamic linq query for the JQWidgets Grid?
Thank you very much.
In what way you are trying to use fieldname variable in where clause ?
If you want to output all columns you can use ToList()
like
var outQuery = Mut.Where("Status = #0 and UserId = #1", "Nieuw", "KLM22940").ToList();
If you want to get some specific columns you can use Select clause like this
var outQuery = Mut.Where("Status = #0 and UserId = #1", "Nieuw", "KLM22940").Select("new(Status,UserId )");
This Select clause creates data class which contains Status and UserId properties and returns a sequence of instances of that data class.

Linq Query with multiple joins and multiple conditions

I am using Telerik Data Access to perform OR mapping.
I am trying to use Linq for performing a join query but not sure how to proceed correctly.
The original sql query is given by:
'SELECT O.OPS_LEG_ID, O.ATD_DATE, O.DEP_AIRPORT_ACT, O.ARR_AIRPORT_ACT, O.ATA_DATE, '+
'O.FL_LOG_ATD_DATE, O.FL_LOG_ATA_DATE, O.FL_LOG_DEP_AIRPORT, O.FL_LOG_ARR_AIRPORT, '+
'O.FL_NB, O.DESIGNATOR, O.FL_LOG_ID, O.FL_LOG_STATUS '+
'FROM CREW_ROT_ROLE CR, OPS_LEG O, CREW_ROLES R, CREW_PAIRING_CMP CP '+
'WHERE CR.ROLE_CDE = R.ROLE_CDE '+
'AND CR.CREW_ROTATION_ID = CP.CREW_ROTATION_ID '+
'AND CP.OPS_LEG_ID = O.OPS_LEG_ID '+
'AND CR.CREW_CDE = :CREW_CDE '+
'AND O.ATD_DATE >= :D_FROM '+
'AND O.ATD_DATE <= :D_TO '+
//'AND R.ROLE_TYPE = 0 '+
'ORDER BY O.ATD_DATE
The corresponding Entities have been generated from the SQL tables. I am now trying to build the equivalent Linq query, which does not seem to work:
var results = from opsLeg in dbContext.OPS_LEGs
from crewRotationRole in dbContext.CREW_ROT_ROLEs
from crewRole in dbContext.CREW_ROLEs
from crewPairingComponent in dbContext.CREW_PAIRING_CMPs
where crewRotationRole.ROLE_CDE == crewRole.ROLE_CDE
&& crewRotationRole.CREW_ROTATION_ID == crewPairingComponent.CREW_ROTATION_ID
&& crewPairingComponent.OPS_LEG_ID == opsLeg.OPS_LEG_ID
&& crewRotationRole.CREW_CDE == userId
select new { OpsLegId = opsLeg.OPS_LEG_ID,
Designator = opsLeg.DESIGNATOR,
FlightNumber = opsLeg.FL_NB
};
Trying the previous query, raises an exception:
"Identifier 'ROLE_CDE' is not a parameter or variable or field of
'FlightLogEntities.OPS_LEG'. If 'ROLE_CDE' is a property please add
the FieldAlias or Storage attribute to it or declare it as a field's
alias."
Not sure how to proceed. What would be the correct query using Linq joins? Thanks!
If you are using a ORM like Entity framework, then the conceptual model would be mix of classes, which would provide a object centric view of data.
So, you would be using the Linq on Objects and in that case you need not write queries for joins as we do in SQL for a database. Conceptual model would contain objects which would be having relationships using navigational properties, and to access navigational properties you can access them as a property of object.
For e.g if there are 2 tables in Database, Customer & Orders. Following SQL statement will return all Orders for Customer number 1:
SELECT Customers.CustomerName, Orders.OrderID
FROM Customers
INNER JOIN Orders
ON Customers.CustomerID=Orders.CustomerID
Where Customers.CustomerID = 1
If we use the EF to generate to generate the conceptual model from Database, we would get class for Customer and Order and Customer class would have a property of ICollection. So, if you need the same results as the SQL query above, you would do it in following way
var CustomerOne = context.Customers.Where(x => x.CustomerID == 1);
var ordersForCustomerOne = CustomerOne.Orders;
You can try something like
var k = from r in dataContext.Order_Details
join t in dataContext.Orders on r.OrderID equals t.OrderID
select r.OrderID ;

Linq To Entities using a view is returning duplicated values

I am using Linq over a View in an SQL Server Database. The concrete sentence is the following:
var valoresFiltrados = Context.VDoNotUse_v2.Select(doNotUse => doNotUse).Where(doNotUse => doNotUse.PlatformValue.Equals(platform) && doNotUse.Bank.Equals(bank) && doNotUse.LanguageValue.Equals("CZE_CZ")).OrderBy(doNotUse => doNotUse.ID);
where VDoNotUse is the View's Entity. This sentece is returning duplicated values (the first IDs are for example 12170, 12171, 12170, 12171, 12204...) and those values are not ordered, as you can see in the example. However, if I use an SqlDataAdapter with the following sentence (which I am sure is the equivalent to the Linq one), it works and returns the correct values:
"SELECT * FROM VDoNotUse_v2 WHERE PlatformValue = '" + platform + "' AND Bank = '" + bank + "' AND LanguageValue = 'CZE_CZ' order by id asc"
Of course, both of them are using the same connection and DataBase.
Does anyone knows why this is happening?
You need to make sure that you have set the entity keys in your entity datamodel to your view correctly. I find that the default entity keys are usually wrong.

Entity Framework query

I have a piece of code that I don't know how to improve it.
I have two entities: EntityP and EntityC.
EntityP is the parent of EntityC. It is 1 to many relationship.
EntityP has a property depending on a property of all its attached EntityC.
I need to load a list of EntityP with the property set correctly. So I wrote a piece of code to get the EntityP List first.It's called entityP_List. Then as I wrote below, I loop through the entityP_List and for each of them, I query the database with a "any" function which will eventually be translated to "NOT EXIST" sql query. The reason I use this is that I don't want to load all the attached entityC from database to memory, because I only need the aggregation value of their property. But the problem here is, the looping will query the databae many times, for each EntityP!
So I am wondering if anybody can help me improve the code to query the database only once to get all the EntityP.IsAll_C_Complete set, without load EntityC to memory.
foreach(EntityP p in entityP_List)
{
isAnyNotComoplete = entities.entityC.Any(c => c.IsComplete==false && c.parent.ID == p.ID);
p.IsAll_C_Complete = !isAnyNotComoplete;
}
Thank you very much!
In EF 4, you can do:
var ids = entityP_List.Select(p => p.ID);
var q = (from p in entities.entityP
where ids.Contains(p => p.ID)
select new
{
ID = p.ID,
IsAll_C_Complete = !p.entityCs.Any(c => !c.IsComplete)
}).ToList();
foreach (var p in entityP_List)
{
p.IsAll_C_Complete = q.Where(e.ID == p.Id).Single().IsAll_C_Complete;
}
...which will do the whole thing in one DB query. For EF 1, Google BuildContainsExpression for a replacement for the .Contains( part of the above.
I would base EntityP on a SQL View instead of a table. Then I would define the relationship, and aggregate the value for child table within the view.

SQLiteException and SQLite error near "(": syntax error with Subsonic ActiveRecord

I ran into an interesting error with the following LiNQ query using LiNQPad and when using Subsonic 3.0.x w/ActiveRecord within my project and wanted to share the error and resolution for anyone else who runs into it.
The linq statement below is meant to group entries in the tblSystemsValues collection into their appropriate system and then extract the system with the highest ID.
from ksf in KeySafetyFunction where ksf.Unit == 2 && ksf.Condition_ID == 1
join sys in tblSystems on ksf.ID equals sys.KeySafetyFunction
join xval in (from t in tblSystemsValues
group t by t.tblSystems_ID into groupedT
select new
{
sysId = groupedT.Key,
MaxID = groupedT.Max(g=>g.ID),
MaxText = groupedT.First(gt2 => gt2.ID ==
groupedT.Max(g=>g.ID)).TextValue,
MaxChecked = groupedT.First(gt2 => gt2.ID ==
groupedT.Max(g=>g.ID)).Checked
}) on sys.ID equals xval.sysId
select new {KSFDesc=ksf.Description, sys.Description, xval.MaxText, xval.MaxChecked}
On its own, the subquery for grouping into groupedT works perfectly and the query to match up KeySafetyFunctions with their System in tblSystems also works perfectly on its own.
However, when trying to run the completed query in linqpad or within my project I kept running into a SQLiteException SQLite Error Near "("
First I tried splitting the queries up within my project because I knew that I could just run a foreach loop over the results if necessary. However, I continued to receive the same exception!
I eventually separated the query into three separate parts before I realized that it was the lazy execution of the queries that was killing me. It then became clear that adding the .ToList() specifier after the myProtectedSystem query below was the key to avoiding the lazy execution after combining and optimizing the query and being able to get my results despite the problems I encountered with the SQLite driver.
// determine the max Text/Checked values for each system in tblSystemsValue
var myProtectedValue = from t in tblSystemsValue.All()
group t by t.tblSystems_ID into groupedT
select new {
sysId = groupedT.Key,
MaxID = groupedT.Max(g => g.ID),
MaxText = groupedT.First(gt2 => gt2.ID ==groupedT.Max(g => g.ID)).TextValue,
MaxChecked = groupedT.First(gt2 => gt2.ID ==groupedT.Max(g => g.ID)).Checked};
// get the system description information and filter by Unit/Condition ID
var myProtectedSystem = (from ksf in KeySafetyFunction.All()
where ksf.Unit == 2 && ksf.Condition_ID == 1
join sys in tblSystem.All() on ksf.ID equals sys.KeySafetyFunction
select new {KSFDesc = ksf.Description, sys.Description, sys.ID}).ToList();
// finally join everything together AFTER forcing execution with .ToList()
var joined = from protectedSys in myProtectedSystem
join protectedVal in myProtectedValue on protectedSys.ID equals protectedVal.sysId
select new {protectedSys.KSFDesc, protectedSys.Description, protectedVal.MaxChecked, protectedVal.MaxText};
// print the gratifying debug results
foreach(var protectedItem in joined)
{
System.Diagnostics.Debug.WriteLine(protectedItem.Description + ", " + protectedItem.KSFDesc + ", " + protectedItem.MaxText + ", " + protectedItem.MaxChecked);
}
Avoid lazy evaluation by forcing an early execution with .ToList() on one of the components of the final query. The results will go into memory so try to make sure you are choosing a small set of data and don't force an unbounded query or gigantic query into a list.

Resources