I've got a problem with Linq2Umbraco at the moment,which is probably due to my poor understanding of LInq. I'm a bit old school for all this fancy new technology ;-)
Here's the Scenario:
I have a collection of content like this, this is the node structure (the doc types are in square brackets)
->Content Folder [contentFolder]
->en-gb [culture]
->packages [packageFolder]
->test package [package]
I want to be able to get "test package" given that I know what a property on test package is and I know the correct culture (there will be duplicate "test package" items in different cultures)
So I need to pass my linq the culture (in this case en-gb) and a property of a package
My first thought was to look in the collection of packages and pick the packages that matched the property then filter down the packages by their grandparent culture.
In XSLT I'd use the ancestor-or-self axis to do this. I tried using the Linq to SQL AncestorOrDefault method but couldn't get it to work.
Any clues on how I could approach this in Linq would be gratefully received.
Linq2Umbraco is missing the Path property which which would have contained the list of parent nodes. I have put in a request to Aaron (@slace) to have this added in the next version. At the moment the Entities in L2U does have the Parent property that returns you the parent object as far as I am aware but you would have to keep walking up through the parents to find the node you wanted this way.
Im not a massive Linq expert but I am sure that there is probably some fancy query that would do that for you in linq.
where packages is your list of packages from the UmbracoDataContext, your package property = something and then walk up the parents until you can limit your result by your culture - assuming Name has the "en-GB" culturecode.
Sounds like the thing to do might be to combine the normal NodeFactory stuff with Linq (so I can grab the path) a bit like this (very much example code!)
This looks in the packages collection for a package with a PackageId of 123
Then it gets the node from the package.Id and splits the path into a collection. It then looks in he path collection again using link to get the cultures collection which is filtered by name.
That's just proof of concept code, but might be an approach. I wonder if it would be easier to extend the base classes to do the path side of things...
Isn't new Node(123) an "expensive" call to the umbraco db? If it still is I wouldn't want to use it in a linq statement..
You could go from top to bottom if you prefer. Simply do multiple select statements untill you have narrowed your results to your package property.
Either way, i think moving up or down serves you better then including nodefactory, but i haven't tried such a combo, so i dont know for sure.
Node(123) is querying the in memory XML node cache so no DB hit at all. Linq to Umbraco is effectively calling the XML Cache anyway so should be no different than calling a Linq query (except for he internal caching Linq to Umbraco does)
Yes - this is what I tried first however I can't get it to work. I've used your code and it still doesn't find the ancestor??
I can't work out what the problem is, everything appears to be in order but it's just not finding the ancestor.
It returns the following error when trying to enumerate the results:
Value cannot be null. Parameter name: attribute
Here's the stack trace:
at System.Xml.Linq.XAttribute.op_Explicit(XAttribute attribute)
at umbraco.Linq.Core.Node.NodeDataProvider.<>c__DisplayClass4.<LoadAncestors>b__3(XElement x)
at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source, Func`2 predicate)
at umbraco.Linq.Core.Node.NodeDataProvider.LoadAncestors(Int32 startNodeId)
at umbraco.Linq.Core.DocTypeBase.AncestorOrDefault[TDocType](Func`2 func)
at umbraco.Linq.Core.DocTypeBase.AncestorOrDefault[TDocType]()
at Website.Extensions.UserControls.Controls.SelectPackageTest.<GetPackageContentItem>b__0(PackagesFolder packages)
at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
at System.Linq.SystemCore_EnumerableDebugView`1.get_Items()
I've had to give up with the AncestorOrDefault method as it just doesn't seem to work for me. I'm wondering if this is because I have quote nested document types?
Anyway I've worked around it for now until I can work out why it's not working or if it's a bug in the implementation of linq2Umbraco.
For reference I'm now doing this in two separate queries, one which finds the culture folder and then one which uses a combination of linq2Umbraco and node factory to check for the culture folder id in the path of the node.
from employeeNode in DigibizDataContext.Employees
where employeeNode.AncestorOrDefault<Home>().Name == language
Query 2
from homeNode in DigibizDataContext.Homes
where homeNode.Name == language
from chamberNode in homeNode.Chambers
from employeeNode in chamberNode.Employees
In Query 1 I look at the parent of each employee. In Query 2 I look at the home node and go down in tree.
There will be about 23 employees. Which would be faster?
Linq2Umbraco query has me stumped
Hi,
I've got a problem with Linq2Umbraco at the moment,which is probably due to my poor understanding of LInq. I'm a bit old school for all this fancy new technology ;-)
Here's the Scenario:
I have a collection of content like this, this is the node structure (the doc types are in square brackets)
->Content Folder [contentFolder]
->en-gb [culture]
->packages [packageFolder]
->test package [package]
I want to be able to get "test package" given that I know what a property on test package is and I know the correct culture (there will be duplicate "test package" items in different cultures)
So I need to pass my linq the culture (in this case en-gb) and a property of a package
My first thought was to look in the collection of packages and pick the packages that matched the property then filter down the packages by their grandparent culture.
In XSLT I'd use the ancestor-or-self axis to do this. I tried using the Linq to SQL AncestorOrDefault method but couldn't get it to work.
Any clues on how I could approach this in Linq would be gratefully received.
Thanks
Tim
Hi Tim,
Linq2Umbraco is missing the Path property which which would have contained the list of parent nodes. I have put in a request to Aaron (@slace) to have this added in the next version. At the moment the Entities in L2U does have the Parent property that returns you the parent object as far as I am aware but you would have to keep walking up through the parents to find the node you wanted this way.
Im not a massive Linq expert but I am sure that there is probably some fancy query that would do that for you in linq.
Peter
With Peters info I guess you could do something like this (of the top of my head):
where packages is your list of packages from the UmbracoDataContext, your package property = something and then walk up the parents until you can limit your result by your culture - assuming Name has the "en-GB" culturecode.
- Morten
Hmmm OK
Sounds like the thing to do might be to combine the normal NodeFactory stuff with Linq (so I can grab the path) a bit like this (very much example code!)
This looks in the packages collection for a package with a PackageId of 123
Then it gets the node from the package.Id and splits the path into a collection. It then looks in he path collection again using link to get the cultures collection which is filtered by name.
That's just proof of concept code, but might be an approach. I wonder if it would be easier to extend the base classes to do the path side of things...
Isn't new Node(123) an "expensive" call to the umbraco db? If it still is I wouldn't want to use it in a linq statement..
You could go from top to bottom if you prefer. Simply do multiple select statements untill you have narrowed your results to your package property. Either way, i think moving up or down serves you better then including nodefactory, but i haven't tried such a combo, so i dont know for sure.
No,
Node(123) is querying the in memory XML node cache so no DB hit at all. Linq to Umbraco is effectively calling the XML Cache anyway so should be no different than calling a Linq query (except for he internal caching Linq to Umbraco does)
T
Sorry, think i confused new Node with new Document.
I will try and digg up some samples tomorrow which will hopefully give you some inspiration for a solution (if Aaron doesnt beat me to it).
You can use the AncestorOrDefault method to do this:
This recurses back up from the current instance and looks for a parent which matches the type (culture) and the selector c.Name == "en-gb"
Awesome - This has just helped me too :)
Yes - this is what I tried first however I can't get it to work. I've used your code and it still doesn't find the ancestor??
I can't work out what the problem is, everything appears to be in order but it's just not finding the ancestor.
It returns the following error when trying to enumerate the results:
Here's the stack trace:
Any clues??
T
Update:
I've had to give up with the AncestorOrDefault method as it just doesn't seem to work for me. I'm wondering if this is because I have quote nested document types?
Anyway I've worked around it for now until I can work out why it's not working or if it's a bug in the implementation of linq2Umbraco.
For reference I'm now doing this in two separate queries, one which finds the culture folder and then one which uses a combination of linq2Umbraco and node factory to check for the culture folder id in the path of the node.
Which is similar to my post above.
T
AncestorOrDefault is working for me.
Now I'd like to know which approach is faster.
I've got the followin structure:
-homeNL
--chamber
---employee1
---employee2
--chamber
---content1
-homeEn
--etc.
I've got the following queries:
Query 1
Query 2
In Query 1 I look at the parent of each employee. In Query 2 I look at the home node and go down in tree.
There will be about 23 employees. Which would be faster?
Jeroen
Since Linq2Umbraco has an AncestorOrDefault method is there also a Descendant method which can go down in the nodes?
No there isn't a infinite depth child option, that'd put a hell of a load of overhead to implement.
You can get type-agnostic children with the Children property, so you could just use a SelectMany to join them all
is working on a reply...