I'm getting lost down the rabbit-hole of EF and Lambdas. I'm trying to get all records from across linking tables.
I'm pretty sure my question is answered here but I can't work out how to apply the answer to my situation.
Here's a simplified model layout of my db.
I'm trying to get a list of all the Speakers for a given event but can't work out how to build the Linq / Lambdas.
To be clear:
An Event can have zero, one or many Sessions
A Session can have zero, one or many Speakers
A Speaker can talk in more than one Session or Event
Any help?
Typically after staring at the problem for over an hour and then posting here I think I've worked it out.
context.SessionSpeakers.Where(x => x.Session.EventId == odv.EventId).Select(x => x.Speaker);
I'll leave this here in case this helps someone else or anyone wants to offer a better answer.
Related
I have this Linq query:
DataBase
.GroupBy(data => new { data.X, data.Y }, (key, group) => new
{
key.X,
key.Y,
Somethings = group.Sum(x => x.Something),
[Code shortened for brevity]
})
.OrderBy(row => row.X)
.ThenBy(row => row.Y)
When using Linq-to-SQL it translates beautifully into the SQL query I was expecting, something like:
SELECT [t1].[x] AS [X], [t1].[y] AS [Y], [t1].[value] AS [Somethings], [...]
FROM (
SELECT SUM([t0].[something]) AS [value], [...], [t0].[x], [t0].[y]
FROM [table] AS [t0]
GROUP BY [t0].[x], [t0].[y]
) AS [t1]
ORDER BY [t1].[x], [t1].[y]
The point above being the SUM performed in the database. However, with Linq-to -Entities in Entity Framework Core (2.0), I get something like the following:
SELECT [data0].[x], [data0].[y], [data0].[something], [...]
FROM [table] AS [data0]
ORDER BY [data0].[x], [data0].[y]
The point this time being no summarizing the data at database level (but rather in memory after all the data has been fetched). It should come as no surprise that this takes a lot longer.
I've searched and found similar questions answered, but nothing that I get in terms of how it translates to my specific query. I have two questions:
How can I produce the optimized result (summarizing at database level) with Linq-to-Entities?
As a bonus, if you know to explain some sort of reasoning behind this all that makes the behavior predictable?
(I know I can execute specific SQL using DbCommand or something, but that's not the answer I'm looking for - I want Linq ;)
[EDIT]
It's been suggested that this question and its answer makes my question a duplicate of the same. I read that Q'n'A, but wasn't satisfied, before posting my own question. Here are some (of my) reasons why that was:
The claim in the answer that GroupBy is always processed in-memory seemed unsubstantiated (but more on that below).
That other question is about a specific query generating (among other things) errors, and the answer contains a solution to that problem which is not applicable to my situation.
That other question - or rather the answer - does not specifically address the performance issues (of my context), and does not contain much of a discussion on how Linq queries translate to SQL in EF Core.
The answer makes claims without referencing versions etcetera, and may soon become obsolete.
So, what about the GroupBy-in-memory claim? Well, I agree that this piece of information is relevant to my case. Obviously summarizing on groups at the database level is not possible if grouping is performed in-memory. In the comments section of the above mentioned answer, there is indeed also a reference to the EF Core Road-map that I overlooked before. From what I gather, proper grouping will be included in the 2.1 release scheduled for Q4 2017.
I now think that the answer to my question here, pending that release of EF Core 2.1, should be a clear reference to the documentation and road-map. It remains to be seen if the actual summarizing problem that I have will be solved along with the grouping issues. (I don't see why it shouldn't, but still...)
Such an answer could be updated when new information becomes available.
I am currently working within Access 2013. I have a simple task that has been really driving me crazy these past few days, as I thought my relationships where correct. But when adding more data into the database I saw that there was a major problem.
Within the database everything is working fine between tblPersonal Information and tblPosition Applied for. The problem that I am running into is trying to successfully create the one to many relationship between tblPosition Applied for and tblOffer
I am trying to make it so that:
one person can apply to many positions (one to many)
one position that each person applies for can have one contingent offer (one to many) "the root of the problem that I am having"
Is their a field that I need to add, or create another table holding just the Personal ID to link tblPosition Applied for and tblOffer? I am really lost on this any help would be greatly appreciated.
If a Position_applied_For can have one-to-many offers, then you need to create a related field in tbl_Offer, just as you did for the one-to-many relationship between tbl_Personal_Information and tblPosition_Applied_For. Change tbl_Offer.Personal_ID to tbl_Offer.Position_Applied_For and relate it back to tblPosition_Applied_For.ID.
Right now there are no fields that are related except Personal_ID in the offers and applied tables. Essentially, there would be no way to distinguish if Person A applied for Job 1 and Job 2, and received an offer for Job 2.
In your tbl_Offer, there should be a Position_ID that relates to the Position. Also, assuming that the offer is only valid for one person, there is no need for tbl_Offer to contain a Personal_ID field, as it would be related through the tblPosition_Applied_For.
I just wanted to validate my data structure.
It seems a bit convoluted to me, maybe it can be simplified?
Questions are grouped into chapters.
For each question, only one answer per session is possible.
The purpose is to be able to compare / analyze answers to the same questions (by different users or by the same users at different times, i.e. with different sessions).
A template, being a collection of chapters & questions, should not have to be replicated, if chapters and questions are the same.
(That would be necessary if Answer did not have a relationship to Session.)
Is the relationship from Answer back to Session the right strategy?
What else would you improve to simplify the model?
Thank you!
EDIT
Follow-up clarification:
The Answer is not static (e.g. "right" answer, "solution"), but some text the user inputs. It is more like a "questionnaire" than a "quiz". The answer has quantitative attributes that can be analyzed.
As stated, one question can have only one answer within a session. Because questions can indirectly belong to more than one session (via (NSSet*) question.chapter.template.sessions), they could have more than one answers and thus need a to-many relationship.
The typical scenario: User starts a new session with a certain template and fills out the answers. Then he can look at the analysis of the results and compare those with the results of other sessions that use the same template.
EDIT 2
The snapshot of the data model including attributes
honestly, this is what I would do instead of your structure, but I don't know what the purpose of the each entity because I'm not able to find out from their simple names.
this is just an idea to resolve the loop.
you can still reach all templates and all answers from the session, not directly but it does not make your life much harder.
UPDATE:
at the first and second sight, for me, it seems the Session entity is just an extra entity only here. honestly you would not need it, if you concatenate with the Template (aka Questionnaire) entity.
you have to add a many-to-many relationship between the Template and User (you can do it, don't worry about it). using this way, from each template you can reach all answers as well, and you won't have any loop.
Despite the really helpful effort by the part of #holex - the best way still seems to be to stick with my design. The simplifications I had hoped for have not materialized.
These day I work with a database that have this style of relationship then I've been very confused with it. This database is in a very large web app & have worked well for 10 years then I wonder whether this design is good in someway? or in which situations I should implement it?
Welcome any idea!
There is nothing wrong in my opinion. You can have, for example, in a personal_data table a place_of_birth field and a place_of_living field both referring to a cities table. By the way you should post a more meaningful example to have a more precise answer.
I have two tables, one with Contacts (people) and another with Addresses.
Gregory Alderson has one Contact entry and two Address entries.
This is the code:
that returns two a records for Gregory Alderson:
If I leave LazyLoadingEnable set to ‘true’, it does the same thing but both records contain both addresses:
The book I’m learning from (Programming Entity Framework 2nd edition – good book BTW) explained that LazyLoading is disabled so the Count method does not impact the results, but so far has not explained why it would do so.
Can someone explain to me why I get two records with LazyLoading turned off, and two records (both with both addresses) with LazyLoading turned on?
A good way to get a better understanding of what's going on is run up Query Analyzer and watch what SQL statements are executed against the db or better yet get a copy of Ayende's EF Profiler.
Essentially with eager loading you need to be more explicit on what related entities you want returned. This is done using the Include method on the context object. Without lazy loading enabled you're making a single hit against the db and then evaluating only against the locally held data rather than making another request to the db for further data used in the Count().
The issue here seems to be due to what you're selecting. Specifically:
select new {a, a.Contact}
Contact is actually a navigation property of a in this case. When you select a, you're selecting everything on a, including Contact. Also selecting a.Contact means you get contact twice.
With lazy loading enabled you don't have to select it. If you select a and then simply use a.Contact somewhere else in your code, EF will go load it for you. The "lazy" in lazy loading is that it's not loaded unless you actually try to use it. With lazy loading on, you just need this:
select a
With lazy loading off, that doesn't happen. But you still don't want to select it. Instead you'd use Include:
from a in context.Addresses.Include("Contact") select a
That tells EF that you always want it to load the Contact navigation property and to do so immediately. It'll be available right away and will still be available if you dispose of the context (which isn't the case with lazy loading).
I suspect the problem here is that by selecting all of a AND a property of a, you're getting a weird side effect.
The OP's question, summed up in the last two paragraphs, was:
The book I’m learning from (Programming Entity Framework 2nd edition – good book BTW) explained that LazyLoading is disabled so the Count method does not impact the results, but so far has not explained why it would do so.
Can someone explain to me why I get two records with LazyLoading turned off, and two records (both with both addresses) with LazyLoading turned on?
The part about the effects of LazyLoading on Count() was explained by Daz. But neither Daz nor Tridus explained why the OP was getting two Contact records for Gregory Anderson in the output regardless of LazyLoading. That is the question that I will answer here.
The problem is that the iteration was essentially happening over Addresses. That is, the outer foreach loop was executing once for each Address in Canada. So because Gregory Anderson has two addresses in Canada, the loop is executed twice for him.
Note that if Gregory Anderson also had an address in the US, the loop would still be executed twice, but all three addresses would be printed out, not just the addresses in Canada.
If the intention was actually to list each Contact once and then list each Address for that Contact, a more appropriate design would be the following:
var contacts = context.Contacts
.Where(c => c.Addresses.Any(a => a.CountryRegion == "Canada"));
foreach (var c in contacts)
{
Console.WriteLine("{0} {1}, Addresses: {2}",
c.FirstName.Trim(),
c.LastName.Trim(),
c.Addresses.Count());
foreach (var a in c.Addresses)
{
Console.WriteLine("...{0}, {1}\n", a.Street1.Trim(), a.City.Trim());
}
}
(I tried to keep the code as close to identical as I could, but I couldn't think of how to write the query using query syntax, so I used LINQ syntax because I'm much more familiar with it...)
This code will result in a distinct list of Contacts being returned from the database and then each Contact will be output one time along with each of the child Addresses.
Hope that helps someone who might be dealing with this and didn't find the other answers helpful on this aspect.