How to access a "Content Picker" value using ModelBuilder
I've been playing with the new ModelBuilder and I was wondering I could access a node that is referenced via a Content Picker using the strongly-typed model.
At the moment, if I do myDocument.myContentPickerContent I get the id of the node referenced via the content picker, just like I would get when using the IPublishedContent interface. But with the TypedContent approach I could do:
Is it good practice, the wiki says that is "ugly" to reference another model from within another model? Or shall I resolve the related node in the controller?
I would recommend using my Core Value Converters v3 package which will strongly type your content pickers as IPublishedContent or you can go further and extend with your own Models.
v3 is currently available as a alpha on MyGet but I'm getting close to release now
There is documentation about the advanced conversions you can do with v3 for Model Builder here
Jeavon
p.s. v2 will work just fine with converting Content Picker to IPublishedContent too but you can use the advanced stuff with v2
Yeah, I was using the Core Value converters with the "normal" approach.
But thinking about it, not sure having the model refer another model is a good idea... how does cache behave in this case? if the main node changes, the cache will refresh, but what if the "linked" model changes?
If the property contains an identifier, and what it should return is something else, then that is the job of a PropertyValueConverter. Which is basically what Jeavon has implemented.
Core should ship with a proper value converter for pickers, that would return an instance of the picked content item. However, that would break compatibility for many sites. This is the sole reason why the current converter still returns an integer. In most cases you will want to replace it by a converter such as Jeavon's.
Keeping a reference to another content item, within a model, can indeed cause caching issues (such as, that other content item is republished but your model isn't aware of it). This is why it is generally considered "ugly".
However, property value converters can declare how they want to cache the value that they return, and there is a mechanism in Core to manage that cache. It is far from perfect but good enough. So what happens is: the property value converter declares that its value should only be cached for the duration of the request, because it is another content item.
Next piece of the puzzle: the converter knows that you have picked "a content item". Unless you write your own specific converter, it cannot know which type of content item your are picking. So the converter, in most cases, declares that it returns an IPublishedContent. And the Models Builder generates:
public IPublishedContent ThatContent
{
get
{
return this.GetPropertyValue<IPublishedContent>("thatContent");
}
}
What-if you know that in your special content, the content picker has been configured to pick content items of type "Pickable"? Either you write you own custom property value converter... or you override the property in a partial class:
[ImplementPropertyType("thatContent")]
public Pickable ThatContent
{
get
{
return this.GetPropertyValue<Pickable>("thatContent");
}
}
When you rebuild the models, the Models Builder will detect that you have implemented the property, and will not implement it.
In v3 we have tried to make it super easy for people to define their special models types and for the rest return IPublishedContent, the multinode tree picker example here is a good one
How to access a "Content Picker" value using ModelBuilder
I've been playing with the new ModelBuilder and I was wondering I could access a node that is referenced via a Content Picker using the strongly-typed model.
At the moment, if I do
myDocument.myContentPickerContent
I get the id of the node referenced via the content picker, just like I would get when using theIPublishedContent
interface. But with theTypedContent
approach I could do:And I would get the node.
How can I obtain the same result using ModelBuilder?
Ideally I'd like to do
Is it good practice, the wiki says that is "ugly" to reference another model from within another model? Or shall I resolve the related node in the controller?
Thx Simone
Hi Simone,
I would recommend using my Core Value Converters v3 package which will strongly type your content pickers as IPublishedContent or you can go further and extend with your own Models.
v3 is currently available as a alpha on MyGet but I'm getting close to release now
There is documentation about the advanced conversions you can do with v3 for Model Builder here
Jeavon
p.s. v2 will work just fine with converting Content Picker to IPublishedContent too but you can use the advanced stuff with v2
Yeah, I was using the Core Value converters with the "normal" approach.
But thinking about it, not sure having the model refer another model is a good idea... how does cache behave in this case? if the main node changes, the cache will refresh, but what if the "linked" model changes?
Let's try to clarify the situation...
If the property contains an identifier, and what it should return is something else, then that is the job of a PropertyValueConverter. Which is basically what Jeavon has implemented.
Core should ship with a proper value converter for pickers, that would return an instance of the picked content item. However, that would break compatibility for many sites. This is the sole reason why the current converter still returns an integer. In most cases you will want to replace it by a converter such as Jeavon's.
Keeping a reference to another content item, within a model, can indeed cause caching issues (such as, that other content item is republished but your model isn't aware of it). This is why it is generally considered "ugly".
However, property value converters can declare how they want to cache the value that they return, and there is a mechanism in Core to manage that cache. It is far from perfect but good enough. So what happens is: the property value converter declares that its value should only be cached for the duration of the request, because it is another content item.
Next piece of the puzzle: the converter knows that you have picked "a content item". Unless you write your own specific converter, it cannot know which type of content item your are picking. So the converter, in most cases, declares that it returns an IPublishedContent. And the Models Builder generates:
What-if you know that in your special content, the content picker has been configured to pick content items of type "Pickable"? Either you write you own custom property value converter... or you override the property in a partial class:
When you rebuild the models, the Models Builder will detect that you have implemented the property, and will not implement it.
Making sense?
Exactly what Stephen said!
In core property value converters we declare our cache level, e.g. https://github.com/Jeavon/Umbraco-Core-Property-Value-Converters/blob/v2/Our.Umbraco.PropertyConverters/ContentPickerPropertyConverter.cs#L159
In v3 we have tried to make it super easy for people to define their special models types and for the rest return IPublishedContent, the multinode tree picker example here is a good one
is working on a reply...