Model generation wizard working backwards or is the programmer backwards? :)

I have a table (again, using the video game stuff as my sample to play with):

ID
Title
Description
Rating (int, refers to the ID column in GameRatings)
Type (int, refers to the ID column in GameTypes)

Rating and Type both have foreign keys that point to the source tables GameRatings and GameTypes respectively. I have Associations in my Entity model that have produced classes called FK_VideoGames_TitleRatings and FK_VideoGames_VideoGameTypes. That all appears fine.

However, I don't appear to have any navigation ability to allow me to do things like:

game.Type.Name or game.Rating.Name

Is there something I missed in the DB to allow for this automatic member generation, or, if the wizard doesn't do it, what do I have to do to my pre-generated model XML in order to give myself those properties



Answer this question

Model generation wizard working backwards or is the programmer backwards? :)

  • KirkAtCenterstance

    Good! It is very reassuring to learn that you are paying so much attention to the guidelines.

    I feel so so about the event idea. On one hand, I think it gives me the greatest degree of control (I could choose to filter or to refuse to load the relationship). On the other hand, you, the framework developer, already know well the code that I, the data layer developer, would want to put in the even handler if I wanted to do implicit lazy loading. I would risk to say that you know it better than me :) Then, why not just let me "explicitly" annotate the navigation property with an attribute that instructs the code generator to write that code for me And what about eager loading Wouldn't it be nice that I could use the same attribute (with a different value) to signal what parts of the graph I want loaded at once

    As a summary of all the cases that have been mentioned: loading="explicit", "implicit", "cached", "eager", "none"  Just kidding ;)

    About raising an error from a property, it is disappointing that the default behavior for a field property in a typed dataset is to raise an exception when you try to read a null value, but that is another story :).

    Really, I don't want to look like I don't like the Entity Framework. On the contrary! And it is great to have this conversation.  



  • AvenueStuart

     Frans Bouma - C# MVP wrote:

    I see little to no value to be able to declaratively force how things are fetched, unless you introduce the concept of 'entity X owns entity Y', as some people want to look at the Order - OrderLine tandem for example: an OrderLine is relatively meaningless with its Order entity.

    Still, I find it incorrect to assume that because an order is loaded you also want the related orderlines, and that it is good that it can be defined with the order to do so. This will cause a lot of extra data to be fetched in situations where it's not important.

    I am not sure that ownership is the only meaningful relationship in this case, but as you say, even in the context of an ownership relationship, it won't always be "correct" to fetch all dependent entities.

    I think that determining when it is convenient depends more on knowledge of the actual access patterns (the use cases that will touch the tables), and on domain knowledge that could give you an idea of how many rows each query will return.

    It is very usual for an architect to be the main source of this kind of knowledge in a team, while less experienced programmers would get better results if provided with a data access layer that worked this automatically.

    Maybe I am wrong, but I see potential in the Entity Framework as tool for this architect (even for a non-coding architect) to build the data access layer direcly while thinking of the "conceptual model". If I am right, then I see value in a tool that lets you declaratively (and visually) embed this behavior in a model (or alongside a model).

    However, it is perfectly good if this is left for third parties or for a future iteration to do. I am operating 100% in exploratory mode.I just wanted to say that it would be interesting that the framework provided the necessary hooks, if possible.

     Frans Bouma - C# MVP wrote:

    Another issue with this is with graphs. What if you want to fetch 10 orders in a collection You then can't fetch the related entities in that same query (you can try with a join, but this will get out of hand pretty quickly so a separate query is often better) so you need to branch out to a different model all of a sudden.

    Well, I am not sure how the Entity Framework would handle this but to do it manually is usually not very difficult. Again, knowledge of the actual access patterns (are multiple orders really going to be fetched at once ) can help you decide when to fetch the dependent entities.

    Something interesting of implementing fetch plans at a higher layer is that you could have multiple fetch plan for the same model (i.e. one for each use case, and something completely different for reporting).



  • Jason N. Gaylord

    DiegoV wrote:

    Yes, I am beginning to agree that this is all good. Maybe it is the best approach to keep things clean at this level. It would also be good to provide the necessary hooks so I can add support for fetch plans in a higher layer if I want to.

    As someone that usually builds the data layer for others to use, I do see much value in being able to declaratively force how things are fetched. All in all, a very interesting conversation.

    I see little to no value to be able to declaratively force how things are fetched, unless you introduce the concept of 'entity X owns entity Y', as some people want to look at the Order - OrderLine tandem for example: an OrderLine is relatively meaningless with its Order entity.

    Still, I find it incorrect to assume that because an order is loaded you also want the related orderlines, and that it is good that it can be defined with the order to do so. This will cause a lot of extra data to be fetched in situations where it's not important.

    Another issue with this is with graphs. What if you want to fetch 10 orders in a collection You then can't fetch the related entities in that same query (you can try with a join, but this will get out of hand pretty quickly so a separate query is often better) so you need to branch out to a different model all of a sudden.


  • jmelvin

    Yes, this is one possibility. Thanks for the suggestion.

    The truth is that there are a lot of different options for how folks might want to specify spans, and there's a fairly large impact to various layers in the stack to make it work. We're actively investigating but don't yet have any firm plans.

    - Danny



  • NLaw

    So, a little more detail.
    This is what came out of the wizard:
    <EntityType Name="VideoGames" Key="ID">
    <Property Name="ID" Type="Int32" Nullable="false" />
    <Property Name="Title" Type="String" Nullable="false" MaxLength="50" />
    <Property Name="Price" Type="Decimal" Nullable="false" Precision="19" Scale="4" />
    <Property Name="Description" Type="String" MaxLength="255" />
    </EntityType>

    The database has columns called Type and Rating, which are both ints. As mentioned above, I have FK associations in there. Out of sheer desperation, I changed the above entity type to:
    <EntityType Name="VideoGames" Key="ID">
    <Property Name="ID" Type="Int32" Nullable="false" />
    <Property Name="Title" Type="String" Nullable="false" MaxLength="50" />
    <Property Name="Price" Type="Decimal" Nullable="false" Precision="19" Scale="4" />
    <Property Name="Description" Type="String" MaxLength="255" />
    <NavigationProperty Name="Type" FromRole="VideoGames" ToRole="VideoGameTypes" Relationship="Self.FK_VideoGames_VideoGameTypes"/>
    </EntityType>

    And then game.Type was null - not at all what I was expecting.

    Any thoughts on whether the wizard missed something in the DB because I didn't set it up properly, or if the programmer (me) is just being an idiot and missing something obvious


  • altamash

    What about Spans as an array of property paths to entities that should be fetched alongside the main entity

    query.AddSpans("OrderLines.Product", "Customer");



  • matt01

    Hi Kevin,

    The changes you made to the EDM schema to add the navigation property look correct.

    The only thing is that when you query for a given entity we don't bring all the reference graph with it (we wouldn't know where to stop and we would risk downloading the whole database :)

    In this CTP the only option we support is explicit delay loading. That means you have to tell the system that you want to resolve/traverse this relationship. You do that by calling the Load() method on the navigation property. If the property points to the "many" side of a relationship then it'll be of type EntityCollection and you can call Load() on that (e.g. Type.Games.Load() to load the games of a given type, assuming you have that navigation property in place); when the property points to the "one" side of a relationship, you have to use the reference that we generate; for example, if you have a property called game.Type you also have one called game.TypeRef. You need to call Load() in the ref, so it would be game.TypeRef.Load(); after doing that, you can use game.Type and it won't be null.

    Let me know if this gives you more trouble and I'll look at it.

    Pablo Castro
    ADO.NET Technical Lead
    Microsoft Corporation



  • Dhiraj Prakash Gupta

    Ok, so my iteration code now looks like this:
    using (GamesDatabase gamesDb = new GamesDatabase())
    {
    var q = from game in gamesDb.VideoGames select game;
    foreach (VideoGames g in q)
    {
    g.TypeRef.Load();
    Console.WriteLine("{0} : {1}", g.Title, g.Type.Name);
    }
    }


    The relationship is defined as the VideoGames being the 0..* part of the multiplicity and the VideoGameTypes table having the 1 multiplicity. While I know that this is technically correct, since there can be game types with no games associated, it may appear backwards to the programmer. Either way, now that I know that I must explicitly load the assocation (which is FANTASTIC because I hated having to manually shut off association loading with DLINQ), things are looking a bit more workable.




  • Brain_Dead_Mind

    Yes, I am beginning to agree that this is all good. Maybe it is the best approach to keep things clean at this level. It would also be good to provide the necessary hooks so I can add support for fetch plans in a higher layer if I want to.

    As someone that usually builds the data layer for others to use, I do see much value in being able to declaratively force how things are fetched. All in all, a very interesting conversation.

    I go to the beach now :)



  • nhaas

    I actually agree that there are scenarios where you want the system to fetch related entities in a single shot. The only thing I don't like is to specify this choice in the definition of the entity or of the relationship. Whether or not you want related entities is something intrinsic to the scenario, not to the entity definition.

    We've have some discussions about allowing the user to indicate what to fetch in the query itself (sometimes referred to as "span" in other ORMs); that's different from "fetch-plans" (again, borrowing from other ORMs) in that fetch plans are in metadata or something like that, instead of being something that's part of your query.

    I think that specifying this as part of the query lets you pull the data you actually need based on the context in which you're executing the query, and will be a more appropriate way of solving that problem.

    All that said, we're still not set with a plan for this, and feedback is very welcome.

    Pablo Castro
    ADO.NET Technical Lead
    Microsoft Corporation



  • hte

    Absolutely! The feedback is super useful--I appreciate having the conversation as well.

    Eager loading is a feature we are well aware of the need for, and it's under investigation. The idea of using an annotation to add implicit loading is also interesting. I'm certainly a fan of doing as much declaratively as we reasonably can, and this is a great example of the kind of thing that we could allow you to specify as an "annotation" on a model which would add optional behavior to the runtime. That's certainly something we'll investigate, but of course there are no firm plans yet.

    - Danny



  • Biggo

    DiegoV wrote:

    Maybe I am wrong, but I see potential in the Entity Framework as tool for this architect (even for a non-coding architect) to build the data access layer direcly while thinking of the "conceptual model". If I am right, then I see value in a tool that lets you declaratively (and visually) embed this behavior in a model (or alongside a model).

    I like the "or alongside a model" part! Having the original metadata express the fetching strategy would be a mistake as Frans mentions, because then we would need multiple copies of the metadata with variations only in the fetching strategies to support various use cases. You could be picturing a set of separate "fetch.xml" files ("alongside the model") which can be attached to a query (hmmm...is that the right place )... (with programmatic support also). As far as "attaching to the query" - maybe there is a higher-level 'use-case' concept to be modeled here, "attaching to the query" is a solution until a 'use-case' concept arrives.

    Cheers,

    -Matthew Hobbs


  • ckrepps

    Given that you can't satisfy everyone all of the time, you can only satisfy some of the people some of the time, the decision to make the system never make unrequested round trips is a perfect solution.

    I would much prefer to have my application come back with a null reference exception that reminds me I didn't explicitly load a NavigationProperty reference as opposed to having the system go hog wild and start querying like a madman without me knowing it.


  • Model generation wizard working backwards or is the programmer backwards? :)