This thread looks to be a little on the old side and therefore may no longer be relevant. Please see if there is a newer thread on the subject and ensure you're using the most recent build of any software if your question regards a particular product.
This thread has been locked and is no longer accepting new posts, if you have a question regarding this topic please email us at support@mindscape.co.nz
|
Hi there, I have the following simple structure:
At the one-to-many relationship I set the "Collection Aggregates" to "T1" this is my test code: LightSpeedContext<DomainUnitOfWork> context = LightSpeedHelpers.Context; And this is the used SQL: SELECT Can someone plase say me what I need to do in order to also select the project's name? The help file is not that helpfull. It didn't say you where you have to do which settings when you search for "WithAggregate". Sörnt
|
|
|
You need to set the Backreference Aggregate. The Collection Aggregate is considered when you load a Project and LightSpeed needs to decide whether to eager-load its Applications collection; but your scenario is that you are loading an Application and LightSpeed needs to decide whether to eager-load its Project backreference. |
|
|
Ahhh - Works like a charm Thank you Sörnt |
|
|
hmm - when I now select the Projects without using WithAggregate I get n+1 selects, when accessing the "Name".
LightSpeedContext<DomainUnitOfWork> context = LightSpeedHelpers.Context;
Does that mean, I now have to allways use "WithAggregate". And If so, can I specify more than one value at the "Aggregates" property (how are they delimeted - ";") ? Sörnt |
|
|
If you make a property part of an aggregate, then it will be lazy-loaded unless you specify that aggregate. You have specified Name as part of an aggregate, so it is not loaded when the rest of the Project object is loaded: it is loaded only when you access the Name property. Hence the n+1 selects: 1 for the non-lazy parts of all the Projects, and n for the n lazy-loads of Name. The solution is to remove the aggregate from Name. Generally you should specify an aggregate only on large properties that are only accessed in specific scenarios (such as image or video blobs). Re multiple aggregates, not quite sure which of the following you mean, but: - To specify in the designer that a property or association is part of multiple named aggregates, separate them with a semicolon (see the little documentation panel under the property grid) - When loading a named aggregate using WithAggregate, you cannot specify multiple aggregates. |
|
|
I want to fine tune the loading graph. It looks to me that Aggregates allows me to do that. Fine tune in terms that I can specifiy which Properties should be loaded, instead of loading a full Entity. What I didn't understand is the situation where I specifiy no Aggregate name (read I don't use "WithAggregate"). When I don't use "WithAggregate" than all properties should be loaded. Here I say "skip the Aggregate-Name comparison". I also hoped that "unitOfWork.Projects.ToList();" is equal to "unitOfWork.Projects.WitAggregate(string.Empty).ToList();" once more I didn't specifiy an Aggregate name, so read the whole Entity. The current situation is not optimal (at least for me :-) ). I need to specify an Aggregate name when I want to load only parts and anotherone when I want to load the full entity. Sörnt |
|
|
"When I don't use "WithAggregate" than all properties should be loaded." No. When you don't use WithAggregate then no named aggregates are loaded. That means that properties which are part of a named aggregate are not loaded. Think about it: if omitting WithAggregate caused all properties to eager-load, how would you lazy load a property? If you left out WithAggregate it would eager load, and if you supplied the aggregate it would eager load too! You'd have to specify WithAggregate with a dummy, nonexistent aggregate name. So omitting WithAggregate has to exclude all aggregates. And therefore if you mark some properties as part of a named aggregate, and you want to eager-load those properties, then you have to specify that you're loading that aggregate. So your final paragraph is correct: if you want to load the full entity, but some of its fields are declared to be part of an aggregate, then you need to specify the aggregate name in the query. You *don't* need to specify an aggregate name when you want to load only parts, assuming that the parts you want are those that are not part of some aggregate. Fields that are not part of an aggregate are always eager-loaded. Of course, if you need more fine tuning than that -- an intermediate option between the minimal "always load" parts (no aggregate) and a maximal "everything" aggregate, then you do need to define an additional aggregate, and use WithAggregate to specify it when appropriate. |
|
|
"Think about it: if omitting WithAggregate caused all properties to eager-load, how would you lazy load a property?" 1. The logic is turned and that will change the behavior of existing code |
|
|
It sounds like you have a very strong mental model of how aggregates should work which is different from how LightSpeed thinks aggregates should work. I'm not sure I fully understand your model, but I'm sure it's equally valid. However, it is different, and we're not planning to change our model at this point. So all I can really do is try to describe how the LightSpeed model works and try to map this onto your use case. As you have identified, making a property part of an aggregate does change the default load behaviour. It takes the property out of the default load set, and makes it part of an optional load set. So yes, if you start moving existing properties into aggregates (optional load sets), you do need to review your existing code to determine whether it needs to include that optional load set. And if you have code which depends on eager-loading the entire entity (as in your dialog example), then you need to define a load set that includes everything (typically called something like "WithAll" or "AllDetails"). The typical expected usage scenario is something like a master-detail view, where you use one load set ("Summary" or just the default load set) for the master page and another load set ("AllDetails") for the detail page. I think the sticking point is that LightSpeed conflates the "minimal" and "default" load sets, which are really separate concepts. It would be nice if we had a way to express subtractive aggregates, so that you could use load sets that are smaller than the default load set. (In your case, I think you want the default load set to be the maximal load set, which means all aggregates would have to be subtractive. But I think you also want additive aggregates -- not sure.) Let me have a look at this and I'll get back to you. |
|
|
I've committed a first pass at subtractive aggregates. The way it works is that if an aggregate name starts with ! (chosen for being the C# syntax for 'not'), then it means 'eager load this property if the aggregate name is NOT specified' -- that is, a property with a ! aggregate will be eager loaded by default, but lazy loaded if the ! aggregate name is specified. So, suppose you have three fields like this: [no aggregates] ContributorId Then: UOW.Contributions -> loads ContributorId and Video Hopefully this will help you implement your desired behaviour. Note that this currently applies only to fields -- associations do not have the special treatment for the ! prefix. I can add this in if it's useful, but I'm holding off until I understand whether this helps with your desired behaviour or not. |
|
|
Thanks for coming back to me! I really want to avoid to add additional aggregate names. Then: UOW.Contributions -> loads ContributorId UOW.Contributions.IgnoreAggregates() -> loads all fields. |
|
|
I'm a little uncertain about your example, because it looks to me like Video and ContributorId should be treated the same -- both are part of no aggregates and therefore both would be loaded in all circumstances. I am guessing that maybe you meant video to be part of a WithBlobs aggregate perhaps? Anyway, I have added a "load all" option. Rather than a new IgnoreAggregates function, there is now a special aggregate name which will load all named aggregates: uow.Contributions.WithAggregate(Query.AllAggregates) -> loads all fields Let us know if you run into any problems! (By the way, since subtractive aggregates didn't prove useful, I have backed them out. So ignore previous message.) |
|
|
Uh, the AllAggregates option will be available in the next nightly build, not right now. |
|
|
Normal 0 21 false false false DE X-NONE X-NONE Let me recapitulate the behavior: There are special fields that seems to be always loaded: # the Primary Key (PK) The designer offers no option to define aggregates for these special fields. In my “Project load” test it loads the PK and RecordVersion field even if they are not part of any aggregates (I didn’t use the other special fields right now). Let me define: Situation a) The Entity has no aggregates defined [no aggregates] ContributorId (PK) Behavior of the normal select: Behavior of WithAggregate(…): Situation b) an Aggregate “WithTitle” is defined: [no aggregates] ContributorId Behavior of the normal select: Behavior of WithAggregate(…): Situation c) That is the new behavior: You defined: What me irritates is the name “Query.AllAggregates” since Video is not part of any aggregates but it should be loaded. Sorry for the rant – I want to make sure we talk about the very same thing – And English isn’t my native language. |
|
|
No worries, I agree that we need to make sure we're not talking past each other! And your examples do clearly illustrate where your model diverges from LightSpeed's. Model Yes, the primary key and special fields are always loaded. Note, however, that the primary key is always Id. The ContributorId in my examples is just an ordinary field, not the ID/PK (a FK as it happens, but that's not important). Situation A In Situation A, where no named aggregates are defined, then WithAggregate() has no effect. It does NOT cause all fields to go lazy. A field can be lazy-loaded only if it is part of a named aggregate. Fields which are not part of a named aggregate are never lazy-loaded. Specifying WithAggregate makes fields which are part of that named aggregate eager -- nothing more. It has no effect on fields which are not part of that named aggregate: they remain eager or lazy depending on whether they are part of some other named aggregate. Consequently, the crucial act that makes a field lazy is not specifying WithAggregate. The act that makes a field lazy is populating its Aggregates setting in the designer. Hence, in Situation A, UOW.Contributions.WithAggregate("WithTitle") would load all three fields because they are always loaded. The presence of the WithTitle aggregate wouldn't add any more, but nor would it remove the existing load-always fields from the load set. Put another way, specifying WithAggregate can only ever result in more fields being loaded, never fewer fields. WithAggregate is always additive, never subtractive. Situation B Similarly, in Situation B, UOW.Contributions loads ContributorId and Video, because both are part of the "always load" set (not part of any named aggregate). UOW.Contributions.WithAggregate("WithTitle") adds the fields that are part of the "WithTitle" aggregate, but does not remove the fields that are not part of that aggregate. So it loads three fields, the two from the "always load" set plus the Title from the "WithTitle" set. WithAggregates(Query.AllAggregates) Hopefully the above makes it clear why I think this name is okay. Fields that are not part of a named aggregate, such as Video, are eager-loaded anyway. Therefore there is no need to specify that fields which are not part of a named aggregate should be eager-loaded. So the only thing the new API needs to do is to add all the fields that are part of some named aggregate -- i.e. to load all named aggregates. |
|
|
Installed the version "LightSpeed31Professional-20101123.msi" and it works like a charm :-) Thank you very much! |
|
|
My issue in understanding the "WithAggregate" was the documentation: I understand that as "only these fields are eager loaded" (and all other fields are lazy loaded). Also the term "Aggregate" within Domain Driven Design (Eric Evans) specifies a group of Entities (with a certain responsibility). So I thought - that is a way to define which Enities belongs together and I also can finetune that down to field level. What I was looking for is more some kind of "FetchGroup". Define an optimized loading graph for the "tagged" fields. So I can specifiy which fields ( and Collections and Backreferences) gets loaded. My understanding now Is that I can define an optimized loading graph by excluding the not needed fields (via an Aggregate defintion) and "join" the needed fields in different loading situations via a named aggregate. Sörnt |
|
|
Yes, your description in the final paragraph is exactly correct. I now see why you found the documentation misleading, and will try to clarify it -- thanks for the feedback! |
|