Eager loading in Entity Framework fails on complex query - entity-framework

The following query fails to load the tables when I execute it:
IEnumerable<Bookmark> tempBookmarks = ListBookmarksByUserID(userID);
IEnumerable<CandidateWithBookmarks> results = (from c in _internshipEntities.CandidateSet
.Include("education")
.Include("progress")
.Include("contacts")
.Include("availability")
.Include("hosttypes")
.Include("hostsizes")
.Include("hostcapacities")
.Include("hoststates")
.Include("users")
join b in tempBookmarks on c.ID equals b.candidates.ID
select new CandidateWithBookmarks()
{CandidateObject = c, BookmarkObject = b});
return results;
I have found some articles related to the problem, namely Alex James' article "How to make Include really Include". The solution comes with one caveat:
For this to work your final select must be entities, i.e. select post rather than select new {…}
Which is obviously an issue for the above block of code. Are there any other known work-arounds for this issue that won't break eager loading?

I think I solved this but it might only work for this specific instance, by moving the includes after the join, the query appears to work:
IEnumerable<CandidateWithBookmarks> results = (
from b in tempBookmarks
join c in _internshipEntities.CandidateSet
.Include("education")
.Include("progress")
.Include("contacts")
.Include("availability")
.Include("hosttypes")
.Include("hostsizes")
.Include("hostcapacities")
.Include("hoststates")
.Include("users")
on b.candidates.ID equals c.ID
select new CandidateWithBookmarks(){CandidateObject = c, BookmarkObject = b});
Edit: Another query I have similar to this requires an outer join as well, which creates some issues since it then matters what you join to what, unlike this example, but it's still doable.

Related

Issue with the join expression in Access 2013

Given below is the sample of my code. When I tried to switch to the design view it gives me an error:
"Microsoft Access can't represent the join expression a.Course_name=b.Course_name in Design view".
When I searched this error on stackoverflow I found one post. According to the post the solution is given in this link (http://support.microsoft.com/kb/207868). According to this link, try to remove extra parenthesis (especially nested parenthesis) and problem will be resolved. However, in my query I don't have nested parenthesis. So I don't know how to fix it. Any help would be appreciated.
SELECT a.Course_name, COUNT(b.Student_code) AS [Total], Format(b.Retrieved_date,"mmmm yyyy") AS [Month]
FROM Course AS a LEFT JOIN (SELECT b.Course_name, b.Student_code, b.Retrieved_date FROM pending-enrolment AS b WHERE b.Retrieved_date BETWEEN [Forms]![ParameterForm]![txtBeginDate] AND [Forms]![ParameterForm]![txtEndDate]) b
ON a.Course_name=b.Course_name
GROUP BY a.Course_name, b.Retrieved_date
;
Try the following code (tested and works 100%):
SELECT Course.Course_name, Count(b.Student_code) AS CountOfStudent_code,
Format([b].[Retrieved_date],"mmmm yyyy") AS [Month]
FROM Course
LEFT JOIN
(
SELECT [pending-enrolment].Course_name, [pending-enrolment].Student_code,
[pending-enrolment].Retrieved_date
FROM [pending-enrolment]
WHERE ([pending-enrolment].Retrieved_date
Between [Forms]![ParameterForm]![txtBeginDate]
And [Forms]![ParameterForm]![txtEndDate])
) AS b ON Course.Course_name = b.Course_name
GROUP BY Course.Course_name, Format([b].[Retrieved_date],"mmmm yyyy");

Assigning a whole DataStructure its nullind array

Some context before the question.
Imagine file FileA having around 50 fields of different types. Instead of all programs using the file, I tried having a service program, so the file could only be accessed by that service program. The programs calling the service would then receive a DataStructure based on the file structure, as an ExtName. I use SQL to recover the information, so, basically, the procedure would go like this :
Datastructure shared by service program :
D FileADS E DS ExtName(FileA) Qualified
Procedure called by programs :
P getFileADS B Export
D PI N
D PI_IDKey 9B 0 Const
D PO_DS LikeDS(FileADS)
D LocalDS E DS ExtName(FileA) Qualified
D NullInd S 5i 0 Array(50) <-- Since 50 fields in fileA
//Code
Clear LocalDS;
Clear PO_DS;
exec sql
SELECT *
INTO :LocalDS :nullind
FROM FileA
WHERE FileA.ID = :PI_IDKey;
If SqlCod <> 0;
Return *Off;
EndIf;
PO_DS = LocalDS;
Return *On;
P getFileADS E
So, that procedure will return a datastructure filled with a record from FileA if it finds it.
Now my question : Is there any way I can assign the %nullind(field) = *On without specifying EACH 50 fields of my file?
Something like a loop
i = 1;
DoW (i <= 50);
if nullind(i) = -1;
%nullind(datastructure.field) = *On;
endif;
i++;
EndDo;
Cause let's face it, it'd be a pain to look each fields of each file every time.
I know a simple chain(n) could do the trick
chain(n) PI_IDKey FileA FileADS;
but I really was looking to do it with SQL.
Thank you for your advices!
OS Version : 7.1
First, you'll be better off in the long run by eliminating SELECT * and supplying a SELECT list of the 50 field names.
Next, consider these two web pages -- Meaningful Names for Null Indicators and Embedded SQL and null indicators. The first shows an example of assigning names to each null indicator to match the associated field names. It's just a matter of declaring a based DS with names, based on the address of your null indicator array. The second points out how a null indicator array can be larger than needed, so future database changes won't affect results. (Bear in mind that the page shows a null array of 1000 elements, and the memory is actually relatively tiny even at that size. You can declare it smaller if you think it's necessary for some reason.)
You're creating a proc that you'll only write once. It's not worth saving the effort of listing the 50 fields. Maybe if you had many programs using this proc and you had to create the list each time it'd be a slight help to use SELECT *, but even then it's not a great idea.
A matching template DS for the 50 data fields can be defined in the /COPY member that will hold the proc prototype. The template DS will be available in any program that brings the proc prototype in. Any program that needs to call the proc can simply specify LIKEDS referencing the template to define its version in memory. The template DS should probably include the QUALIFIED keyword, and programs would then use their own DS names as the qualifying prefix. The null indicator array can be handled similarly.
However, it's not completely clear what your actual question is. You show an example loop and ask if it'll work, but you don't say if you had a problem with it. It's an array, so a loop can be used much like you show. But it depends on what you're actually trying to accomplish with it.
for old school rpg just include the nulls in the data structure populated with the select statement.
select col1, ifnull(col1), col2, ifnull(col2), etc. into :dsfilewithnull where f.id = :id;
for old school rpg that can't handle nulls remove them with the select statement.
select coalesce(col1,0), coalesce(col2,' '), coalesce(col3, :lowdate) into :dsfile where f.id = :id;
The second method would be easier to use in a legacy environment.
pass the key by value to the procedure so you can use it like a built in function.
One answer to your question would be to make the array part of a data structure, and assign *all'0' to the data structure.
dcl-ds nullIndDs;
nullInd Ind Dim(50);
end-ds;
nullIndDs = *all'0';
The answer by jmarkmurphy is an example of assigning all zeros to an array of indicators. For the example that you show in your question, you can do it this way:
D NullInd S 5i 0 dim(50)
/free
NullInd(*) = 1 ;
Nullind(*) = 0 ;
*inlr = *on ;
return ;
/end-free
That's a complete program that you can compile and test. Run it in debug and stop at the first statement. Display NullInd to see the initial value of its elements. Step through the first statement and display it again to see how the elements changed. Step through the next statement to see how things changed again.
As for "how to do it in SQL", that part doesn't make sense. SQL sets the values automatically when you FETCH a row. Other than that, the array is used by the host language (RPG in this case) to communicate values back to SQL. When a SQL statement runs, it again automatically uses whatever values were set. So, it either is used automatically by SQL for input or output, or is set by your host language statements. There is nothing useful that you can do 'in SQL' with that array.

Using #FetchGroup with eclipseLink

I have tried to get source running as explained in http://eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_fetchgroup.htm
#FetchGroup(name="names",
attributes={
#FetchAttribute(name="firstName"),
#FetchAttribute(name="lastName")
})
TypedQuery query = em.createQuery("SELECT e FROM Employee e", Employee.class);
query.setHint(QueryHints.FETCH_GROUP_NAME, "names");
Sadly it ends up with "Needs to implement FetchGroupTracker".
I don't know if it is really the case or I'm missing something. Does anybody know where I can find a sample for it?
You must set up byte code weaving/enhancement for this to work automatically, otherwise your entities will need to implement the FetchGroupTracker class so that the fetch group attributes can be put into and used by your entity. See https://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Advanced_JPA_Development/Performance/Weaving

use of variable causes update to run very slow

I have the following query.
UPDATE t
SET UnitsSold = sub.UnitsSold,
FROM dbo.table1 t
JOIN (SELECT s.CustomerKey,
s.WeekKey,
s.ProductKey,
Sum(s.UnitsSold) AS [UnitsSold],
FROM dbo.table2 s
WHERE WeekKey >= 335
GROUP BY s.WeekKey,
s.CustomerKey,
s.ProductKey) AS sub
ON sub.WeekKey = t.WeekKey
AND sub.CustomerKey = t.CustomerKey
AND sub.ProductKey = t.ProductKey
It runs like a champ. About 2 seconds. Then when try and make it dynamic via the following.
DECLARE #StartWeekKey AS INT
SET #StartWeekKey = 335
UPDATE t
SET UnitsSold = sub.UnitsSold,
FROM dbo.table1 t
JOIN (SELECT s.CustomerKey,
s.WeekKey,
s.ProductKey,
Sum(s.UnitsSold) AS [UnitsSold],
FROM dbo.table2 s
WHERE WeekKey >= #StartWeekKey
GROUP BY s.WeekKey,
s.CustomerKey,
s.ProductKey) AS sub
ON sub.WeekKey = t.WeekKey
AND sub.CustomerKey = t.CustomerKey
AND sub.ProductKey = t.ProductKey
All of a sudden, it's super slow.
any good ideas?
EDIT:
Probalby should have mentioned this, but this is contained in a stored proc.
Added the #StartWeekKey as a parameter to the proc and it goes back to running in a few seconds.
This question seems to have been asked several times before and the general answer is that it has to do with statistics.
Try:
UPDATE STATISTICS table_or_indexed_view_name
to get your statistics up to date and see if that makes a difference.
That isn't unheard of when different parameters have very different distributions, thus different good plans. What can happen is that the query gets executed for a given value, and then that plan gets cached and re-used inappropriately for a different value.
If this is the case (just a guess - I can't run your query to check!) then try adding:
OPTION (OPTIMIZE FOR (#StartWeekKey UNKNOWN))
to the end of the query.
Another thought: is WeekKey actually an int ? is this some kind of mass type conversion issue?
I have no way of checking these; if I'm miles off the track, let me know so I can remove an unhelpful answer.

Versant OQL Statement with an Arithmetic operator

I'm working on a c# project that use a Versant Object Database back end and I'm trying to build a query that contains an arithmetic operator. The documentation states that it is supported but lack any example.
I'm trying to build something like this:
SELECT * FROM _orderItemObject WHERE _qtyOrdered - _qtySent > 0
If I try this statement in the Object Inspector I get a synthax error near the '-'.
Anyone has an example of a working VQL with that kind of statement?
Thanks
I am not sure that the Object Inspector will know the syntax for the arithmtic expression. However, in your code you should be referring to the fully qualified class. Then the syntax you are using should be perfectly fine.
Query query = new Query( session,
"select * from com.yourCompany.yourClass where _qtyOrdered - _qtySent > 0 ");
QueryResult result = query.execute();
I just tried this out on one of my classes and it worked fine.
Cheers,
-Robert
With C# and OQL you have to make sure you select the proper class extent. This is done by adding the "Extent" suffix to the class name. For example, in my Pet class I would identify all the pets with "PetExtent" in the OQL string.
Class members are accessed in the predicate by defining a local moniker, p in the code below. Any arithmetic expressions will be evaluated by the query engine.
string query="SELECT * FROM PetExtent AS p WHERE p.Name = \"Ferris\" AND (p.age + 5) > 4";
IQueryResult result = scope.GetOqlQuery(query).Execute();
foreach (object o in result)
Out(o.ToString());
The best way to test OQL with Versant's C# binding is to use the OQL Query Browser integrated into Visual Studio. Look under the Versant Menu drop down in Visual Studio.
Best Regards,
Derek