MarkLogic Java Client JSONDocumentManager word search returns incorrect total number of results - marklogic-10

jsonDocumentManager.setPageLength(pagination.getItemsPerPage());
var offset = ((pagination.getPage() - 1) * pagination.getItemsPerPage()) + 1;
try (var documentPage = jsonDocumentManager.search(queryDefinition, offset)) {
var results = new ArrayList<TransportOrder>();
for (var documentRecord : documentPage) {
try {
var jsonParser = documentRecord.getContent(new JacksonParserHandle()).get();
...
} catch (IOException e) {
System.out.println("Something went wrong");
}
}
var totalNumberOfResults = documentPage.getTotalSize();
System.out.println("totalNumberOfResults : " + totalNumberOfResults);
}
}
where the queryDefinition contains multiple word queries:
qb.word(qb.jsonProperty(searchField), StructuredQueryBuilder.FragmentScope.DOCUMENTS,
new String[] {"wildcarded"}, 1.0, wildcardString);
The problem is the totalNumberOfResults is the total items from the database not only the items that match the search criteria. It is mentioned in the documentation for getTotalSize that: "The total count (most likely an estimate) of all possible items in the set."
I need to get somehow the actual number of items found by the search. Any idea how I can achieve this?
https://docs.marklogic.com/javadoc/client/com/marklogic/client/Page.html#getTotalSize--

Related

Xamarin.Android How to Get Google Play Store app version number using Dcsoup Nuget Plugin?

I am trying to get the latest version number of my store app in order to notify user for updates if they are using an older version.
This is my code so far but its obviously just retrieving the div containing the text "Version Number". How do I get the actual version number (in this case 1.1) referring to the attached screenshot of the DOM tree?
public static string GetAndroidStoreAppVersion()
{
string androidStoreAppVersion = null;
try
{
using (var client = new HttpClient())
{
var doc = client.GetAsync("https://play.google.com/store/apps/details?id=" + AppInfo.PackageName + "&hl=en_CA").Result.Parse();
var versionElement = doc.Select("div:containsOwn(Current Version)");
androidStoreAppVersion = versionElement.Text;
}
}
catch (Exception ex)
{
// do something
Console.WriteLine(ex.Message);
}
return androidStoreAppVersion;
}
According to the parser doc,the containsOwm selector selects elements that directly contain the specified text.
As a result, your code
var versionElement = doc.Select("div:containsOwn(Current Version)");
will surely return "Current Version". The real element you would like to get is the child of the child of the sibling of "Current Version" element. So you would have to get that element using the selector.
So you can get the version number in this way:
var versionElement = doc.Select("div:containsOwn(Current Version)");
Element headElement = versionElement[0];
Elements siblingsOfHead = headElement.SiblingElements;
Element contentElement = siblingsOfHead.First;
Elements childrenOfContentElement = contentElement.Children;
Element childOfContentElement = childrenOfContentElement.First;
Elements childrenOfChildren = childOfContentElement.Children;
Element childOfChild = childrenOfChildren.First;
androidStoreAppVersion = childOfChild.Text;

RavenDb Suggestions - return multiple-contexts words

I'm trying to get context based suggestions result from RavenDb, the purpose is ui dropdown with auto suggestion from large amount of data on server, each keystroke (in 400ms) is sent to retrieve suggestions.
The suggestion i need is with multiple words by context.
let's say i'm looking for 'Harry Potter', i have documents with just 'Harry' and some docs with only 'Potter', and documents with both.
But if i type 'harre poter' i would get one word suggestions.
i tried searching with multiple words (demonstrated here - suggest.Term = "(word1 word2)";), but the result is list of one words. i want to type 'harre poter' and get suggestion of 'Harry Potter'
i even tried querying multiple times with each word, but the result are not context based, in other word - there is no connection between them.
var words = text.Split(new String[] {" "}, StringSplitOptions.RemoveEmptyEntries).ToList();
var sugegstions = new List<SuggestionQuery>();
foreach (var word in words)
{
var suggest = new SuggestionQuery();
suggest.Field = "Body";
suggest.Term = word;
suggest.Popularity = true;
suggest.MaxSuggestions = 5;
suggest.Distance = StringDistanceTypes.Levenshtein;
sugegstions.Add(suggest);
}
var results = new List<SuggestionQueryResult>();
foreach (var suggest in sugegstions)
{
SuggestionQueryResult result =
s.Query<Book, Books_ByBody>().Suggest(suggest);
results.Add(result);
}
i looked in this SO question, and tried it too, but the results are the docs not suggestions.
my index is : `
public class Books_ByBody : AbstractIndexCreationTask
{
public Books_ByBody()
{
Map = books from book in books
select new
{
book.Body,
};
Indexes.Add(x => x.Body, FieldIndexing.Analyzed);
Suggestion(x => x.Body);
}
}
`

Retrieve reference to comment OpenXML

I am trying to pull out the text from a Word document that is referenced by a comment in OpenXML. I can easily get the text of a comment, but not the paragraph text in the document that the comment is referencing.
The image I attached shows a comment and the related text. I am having a lot of trouble finding an example of how to get the referenced text. How can I get this text?
The solution is to get the Id of the comment which as you said you already know how to retrieve, and then search the document for a CommentRangeStart element with the same Id. When you have found it, you can loop over .NextSibling() until you hit a CommentRangeEnd element.
The elements between CommentRangeStart and CommentRangeEnd is the referenced part, which obviously can be multiple runs, paragraphs, images, whatever. So you will have to handle the collected elements somehow afterwards.
I made a test document looking like this:
I've made this code to test it:
using (var wordDoc = WordprocessingDocument.Open(#"c:\test\test.docx", true))
{
MainDocumentPart mainPart = wordDoc.MainDocumentPart;
var document = mainPart.Document;
var comments = mainPart.WordprocessingCommentsPart.Comments.ChildElements;
foreach(Comment comment in comments)
{
string commentId = comment.Id;
string commentText = comment.InnerText;
OpenXmlElement rangeStart = document.Descendants<CommentRangeStart>().Where(c => c.Id == commentId).FirstOrDefault();
List<OpenXmlElement> referenced = new List<OpenXmlElement>();
rangeStart = rangeStart.NextSibling();
while(!(rangeStart is CommentRangeEnd))
{
referenced.Add(rangeStart);
rangeStart = rangeStart.NextSibling();
}
Console.WriteLine("Comment Id " + commentId + " with text \"" + " " + commentText + "\" references =>");
foreach (var ele in referenced)
{
if(!string.IsNullOrWhiteSpace(ele.InnerText))
{
Console.WriteLine(" " + ele.InnerText);
}
}
}
Console.ReadKey();
}
Which produces this output
I hope it helps!
I could not get your solution to work. However I found a workaround.
OpenXmlElement rangeStart = document.Descendants<CommentRangeStart>().Where(c => c.Id == commentId).FirstOrDefault();
bool breakLoop = false;
rangeStart = rangeStart.Parent;
while (true) // Looping through items between commentRangeStart and commentRangeEnd.
{
if (rangeStart.NextSibling() == null)
{
break;
}
foreach (var ele in rangeStart.ChildElements)
{
if (!(ele is CommentRangeEnd))
{
if (!(string.IsNullOrWhiteSpace(ele.InnerText)))
{
referenced.Add(ele);
}
}
else
{
breakLoop = true;
}
if (breakLoop)
break;
}
rangeStart = rangeStart.NextSibling();
}
Hence, instead of looping through the paragraph in which the CommenRageStart exists, since one comment may be built up of several paragraphs, I use the parent node in order to trace back and forth between the paragraphs. Finnaly, as I reach the CommentRangeEnd I can break the loop and process the data however is required.

Nesting Model Reports + Search Results

Seem like I'm not the first to investigate this. But not despairing yet :-)
The target state I'd like to reach is:
A recursion through Packages, where some of the nested Sub-Packages are glorified Linked Documents, and some are Grids rendering Search Results.
I like that Model Documents provide Search Tag values -- but I can't seem to nest the grids where I want them to show up.
Approach 1: Nested Model Documents
If I could nest Model Document elements, with their Search/Search Term tags, I would be sorted. I could have
Context:Package
Introduction:Package <- just renders a Linked Document attached to it
Systems Affected:Package <- just renders a Linked Document attached to it
Systems Affected:Model Document <- renders the results of a canned Search.
But EA appears to be designed to ignore the Model Document element.
Approach 2: SQL backed Template Fragment
I like the Model Document as it has Search/Search Term + all the Inclusion/Exclusion configuration options. But if I had to give that part up I am thinking of emulating as much as I can via SQL or script.
First attempt - using SQL and a nested set of Packages such as:
Context:Package
Introduction:Package <- just renders a Linked Document attached to it
Systems Affected:Package <- just renders a Linked Document attached to it
Systems Affected:Package<> <- renders the results of a SQL Search.
If the template uses a TemplateSelector it can spot the Package with a wellknown stereotype, and invoke a Template that is backed by SQL.
The SQL uses the Package's Keywords as the source of the Element type to search for.
SELECT
o.ea_guid AS [CLASSGUID],
o.Object_Type AS [CLASSTYPE],
o.PDATA5 AS [KEYWORDS],
o.Object_Type AS [Type],
o.Stereotype AS [Stereotype],
*
FROM t_object as O
WHERE O.Object_Type IN
(SELECT PDATA5 FROM t_object AS S where S.Object_ID = #OBJECTID#)
It works...barely.It's a bit hacky.
Searching off of Element Type is not going to be sufficient for production documents.
Approach 3: Script backed Template Fragment
If I can get a script running I suspect that I could leverage functionality that is already in the system.
Context:Package
Introduction:Package <- just renders a Linked Document attached to it
Systems Affected:Package <- just renders a Linked Document attached to it
Systems Affected:Package<> <- renders the results of a canned Search.
If the template uses a TemplateSelector it can spot the Package with a wellknown stereotype, and invoke a Template that is backed by a script.
The script I'm trying is:
var x = Repository.GetElementsByQuery("POC.Req", "Device");
return x;
But the report remains blank of those elements I need for the table.
Q: Does the returned Collection need transformation before it can be used?
Approach 4
I've heard that there is an approach to Render Document sections as PDF, and link to them as Linked Documents... Sounds Convoluted. Sounds like a wrong/magic approach.
Approach 5
Any other suggestions?
Thanks for the help.
Addendum
Just got approach 3 to work by converting the script results to xml before handing it back
The template's script now looks like
-- first pass ...I'll work on passing the ObjectId in a bit in order to get fancier.
ExecuteSearch("Simple", "Device")
and it invokes a script saved somewhere else as
!INC Local Scripts.EAConstants-JScript
/*
* Script Name:
* Author:
* Purpose:
* Date:
*/
function main()
{
return ExecuteSearch("Simple", "Device");
}
function ExecuteSearch(searchName, searchParam){
var x = Repository.GetElementsByQuery(searchName, searchParam);
//return x;
var xmlDOC = CreateReport(x);
var s = xmlDOC.xml;
Session.Output(s);
return s;
}
function CreateReport(entityCollection){
var xmlDOC = CreateXmlDOC();
var xmlRoot = AppendXmlChild(xmlDOC,"EADATA");
var xmlDataSet = AppendXmlChild(xmlDOC,"Dataset_0",xmlRoot);
var xmlData = AppendXmlChild(xmlDOC,"Data",xmlDataSet);
for(var i = 0;i<entityCollection.Count();i++){
var entity = entityCollection.GetAt(i);
var xmlRow = AppendXmlChild(xmlDOC,"Row",xmlData);
//AppendXmlChild(xmlDOC,"CLASSTYPE",xmlRow).Text = entity.Type;
AppendXmlChild(xmlDOC,"Guid",xmlRow).text = entity.ElementGUID;
AppendXmlChild(xmlDOC,"CLASSTYPE",xmlRow).text = entity.Type;
AppendXmlChild(xmlDOC,"CLASSGUID",xmlRow).text = entity.ElementGUID;
AppendXmlChild(xmlDOC,"Type",xmlRow).text = entity.Type;
AppendXmlChild(xmlDOC,"Stereotype",xmlRow).text = entity.Stereotype;
AppendXmlChild(xmlDOC,"Name",xmlRow).text = entity.Name;
AppendXmlChild(xmlDOC,"Object",xmlRow).text = entity.Name;
AppendXmlChild(xmlDOC,"Id",xmlRow).text = entity.ElementID;
AppendXmlChild(xmlDOC,"Scope",xmlRow).text = entity.Scope;
AppendXmlChild(xmlDOC,"Phase",xmlRow).text = entity.Phase;
AppendXmlChild(xmlDOC,"Status",xmlRow).text = entity.Status;
var noteElement = AppendXmlChild(xmlDOC,"Notes",xmlRow);//.text = entity.Notes;
noteElement.appendChild(xmlDOC.createCDATASection(entity.Notes));
AppendXmlChild(xmlDOC,"Keywords",xmlRow).text = entity.PDATA5;
}
return xmlDOC;
}
function CreateXmlDOC()
{
var xmlDOM;
try
{
xmlDOM = new ActiveXObject( "MSXML2.DOMDocument.4.0" );
}
catch(e)
{
xmlDOM = new ActiveXObject( "MSXML2.DOMDocument.6.0" );
}
xmlDOM.createProcessingInstruction("xml","version=\"1.0\"");
xmlDOM.validateOnParse = false;
xmlDOM.async = false;
return xmlDOM;
}
function AppendXmlChild(xmlDOM, xmlElementName, xmlParent, isCDATA){
if (!xmlParent){xmlParent = xmlDOM;}
var child = xmlDOM.createElement(xmlElementName);
xmlParent.appendChild(child);
return child;
}
main();
The script I used in the end is as follows. It now correctly investigates the element's tags for clues as how to proceed.
Hope it helps others.
!INC Local Scripts.EAConstants-JScript
/*
* Script Name:
* Author:
* Purpose:
* Date:
*/
//Only used for development
function devTest()
{
//With Child elements: {2255D8C8-F1BB-4069-BDAF-8B303D108C62}
//With SearchName: {919252E0-BDEB-4f26-A39F-C0E74382952A}
//With PackageGUID: {8543ED3B-EC39-4bf0-92C2-FD49A00C376B}
Session.Output ("DEVTEST");
var package = Repository.GetPackageByGuid("{8543ED3B-EC39-4bf0-92C2-FD49A00C376B}");
Session.Output("Package Name:" + package.Name);
Session.Output("Package Guid:" + package.PackageGUID);
Session.Output("Package Id:" + package.PackageID);
Session.Output("Package ElementId:" + package.Element.ElementID);
//Session.Output("Package Element Id:" + package.Element.ElementID);
//Use the Element associate to the Package, not the Package ID itself.
var packageElementId = package.Element.ElementID; //NOT: package.PackageID;
var xmlDoc=ExecuteSearch(packageElementId);
try {
Session.Output(xmlDoc.xml);
}catch (e){
Session.Output(e.message);
}
}
//Extracts from a given Package it's SearchName/SearchValue tags
//in order to do a search that mimicks a ModelDocument's way of
//generating a report.
function ExecuteSearch(elementId){
//Validation
if (!elementId){
Session.Output("Exiting: No elementId received.");
return;
}
var packageElement = Repository.GetElementByID(elementId);
if (!packageElement){
Session.Output("Exiting: No package with given elementId: " + elementId);
return;
}
try {
var xmlDOC = ExecuteSearch2(packageElement);
var xml = xmlDOC.xml;
return xml;
}catch (e){
Session.Output("ERROR: " + e.message);
}
return null;
}
function ExecuteSearch2(packageElement){
//Session.Output(packageElement.ElementGUID + ": '" + packageElement.Name + "' invoking ExecuteSearch(" + packageElement.ElementID + ")");
//Session.Output("Attribute 'Test': " + GetElementTaggedValue(packageElement,'Test'));
//Precendence is to search
//* Direct children,
//* by Package, recursively,
//* Package, single
//* Package
//First dibs: does this package have any direct elements?
//Get back to the package that is related to the Element before you count Elements:
var package = Repository.GetPackageByGuid(packageElement.ElementGUID);
var elementCollection = package.Elements;
if (elementCollection.Count()){
Session.Output("Package [" + packageElement.ElementGUID + "] has child Elements:"+ elementCollection.Count());
return CreateReportDoc(elementCollection);
}
//If package had no children, look at Attributes for reference to other package.
//At present, can't find an easy way to determine package Id from the EA GUI, so
//using the Guid.
var searchPackageGuid = GetElementTaggedValue(packageElement,'SearchPackageGUID');
if (!searchPackageGuid){
searchPackageGuid = GetElementTaggedValue(packageElement,'SearchPackageGuid');
}
if (searchPackageGuid){
//Session.Output("Package [" + packageElement.ElementGUID + "] has SearchPackageGuid:"+ searchPackageGuid);
return ExecuteSearchByPackageGuid(searchPackageGuid);
}
// //If I ever find a way to get a packageId:
var searchPackageId = GetElementTaggedValue(packageElement,'SearchPackageId');
if (searchPackageId){
//Session.Output("Package [" + packageElement.ElementGUID + "] has SearchPackageId:"+ searchPackageId);
return ExecuteSearchByPackageId(searchPackageId);
}
// //If searching by SQL:
var searchSQL = GetElementTaggedValue(packageElement,'SearchSQL');
if (searchSQL){
Session.Output("Package [" + packageElement.ElementGUID + "] has SearchSQL:"+ searchSQL);
return ExecuteSearchBySQL(searchSQL);
}
//Not pointing to a package, so maybe pointing to a canned search:
var searchName = GetElementTaggedValue(packageElement,'SearchName');
if (!searchName){
//Session.Output("No SearchName");
return;
}
var searchValue = GetElementTaggedValue(packageElement,'SearchValue');
//Session.Output("Package [" + packageElement.ElementGUID + "] has SearchName/Value:"+ searchName + "/" + searchValue);
return ExecuteSearchBySearchName(searchName, searchValue);
}
//Mimicks functionality of a ModelDocument that searches by canned SearchName/SearchValue.
function ExecuteSearchBySearchName(searchName, searchValue){
var elementCollection = Repository.GetElementsByQuery(searchName, searchValue);
//return x;
return CreateReportDoc(elementCollection);
}
function ExecuteSearchByPackageGuid(packageGuid){
var package = Repository.GetPackageByGuid(packageGuid);
return ExecuteSearch2(package.Element);
}
function ExecuteSearchBySQL(searchSQL){
var elementCollection = Repository.GetElementSet(searchSQL, 2);
}
function HOLD_ExecuteSearchBySet(idList){
var elementCollection = Repository.GetElementsSet(idList);
//return x;
return CreateReportDoc(elementCollection);
}
//Iterate through the elements and convert to an Xml Document
//suitable for use by a Script backed Template:
function CreateReportDoc(elementCollection){
var xmlDOC = CreateXmlDOC();
var xmlData = CreateXmlReport(xmlDOC);
for(var i = 0;i<elementCollection.Count();i++){
//For each Element, create a new row:
var xmlRow = AppendXmlChild(xmlData,"Row");
//And embed the specific element:
var element = elementCollection.GetAt(i);
CreateReportRow(xmlRow, element);
}
return xmlDOC;
}
function CreateReportRow(xmlRow, element){
//And attach child property elements.
//For hairy ones, add them as a CDATA.
//AppendXmlChild(xmlDOC,"CLASSTYPE",xmlRow).Text = element.Type;
AppendXmlChild(xmlRow,"Guid").text = element.ElementGUID;
AppendXmlChild(xmlRow,"CLASSTYPE").text = element.Type;
AppendXmlChild(xmlRow,"CLASSGUID").text = element.ElementGUID;
AppendXmlChild(xmlRow,"Type").text = element.Type;
AppendXmlChild(xmlRow,"Stereotype").text = element.Stereotype;
AppendXmlChild(xmlRow,"Name").text = element.Name;
AppendXmlChild(xmlRow,"Object").text = element.Name;
AppendXmlChild(xmlRow,"Id").text = element.ElementID;
AppendXmlChild(xmlRow,"Scope").text = element.Scope;
AppendXmlChild(xmlRow,"Phase").text = element.Phase;
AppendXmlChild(xmlRow,"Status").text = element.Status;
AppendXmlChild(xmlRow,"Keywords").text = element.PDATA5;
//Notes need wrapping as CDATA
var noteElement = AppendXmlChild(xmlRow,"Notes");//.text = entity.Notes;
noteElement.appendChild(xmlRow.ownerDocument.createCDATASection(element.Notes));
//Now get tags:
AppendXmlChild(xmlRow,"Tags.ID").text = GetElementTaggedValue(element,"ID");
AppendXmlChild(xmlRow,"Tags.Type").text = GetElementTaggedValue(element,"Type");
AppendXmlChild(xmlRow,"Tags.Category").text = GetElementTaggedValue(element,"Category");
AppendXmlChild(xmlRow,"Tags.Traceability").text = GetElementTaggedValue(element,"Traceability");
return xmlRow;
}
//helper function to create an empty xml document
function CreateXmlDOC()
{
var xmlDOM;
try
{
xmlDOM = new ActiveXObject( "MSXML2.DOMDocument.4.0" );
}
catch(e)
{
xmlDOM = new ActiveXObject( "MSXML2.DOMDocument.6.0" );
}
xmlDOM.createProcessingInstruction("xml","version=\"1.0\"");
xmlDOM.validateOnParse = false;
xmlDOM.async = false;
return xmlDOM;
}
//helper function to create the beginning of an xml document
//suitable to render the results of a search:
function CreateXmlReport(xmlDOC){
var xmlRoot = AppendXmlChild(xmlDOC,"EADATA");
var xmlDataSet = AppendXmlChild(xmlRoot,"Dataset_0");
var xmlData = AppendXmlChild(xmlDataSet,"Data");
return xmlData;
}
//helper function to attach a new child xml element to a parent xml element
function AppendXmlChild(xmlParent, xmlElementName, isCDATA){
var xmlDocument = xmlParent.ownerDocument;
if (!xmlDocument){xmlDocument = xmlParent}
var child = xmlDocument.createElement(xmlElementName);
xmlParent.appendChild(child);
return child;
}
//Gets an Element's tag. Eats exception if Tag does not exist.
function GetElementTaggedValue(element, tagName){
var tag;
try {
tag = element.TaggedValues.GetByName(tagName);
}
catch (e) {
}
if (!tag){return;}
var result = tag.Value;
return result;
}
function ConvertPackageIdToBranchId(packageId){
var package = Repository.GetPackageByID(objectId);
if (!package){return;}
var packages = [package];
packages.concat(ConvertPackageToBranch(package));
var result=[];
for(var i=0;i<packages.length;i++){
result.push(packages[i].PackageID);
}
return result;
}
function ConvertPackageToBranch(package){
var result = [];
for (var i=0;i<package.Packages.Count();i++){
var childPackage = package.Packages.GetAt(i);
result.push(childPackage);
result.concat(ConvertPackageToBranch(childPackage));
}
return result;
}
//devTest();

Relational Queries In parse.com (Unity)

I found example in parse.com. I have 2 objects : Post and Comment, in the Comment objects have a collumn: "parent" pointer to Post obj and I want to join them:
var query = ParseObject.GetQuery ("Comment");
// Include the post data with each comment
query = query.Include("parent");
query.FindAsync().ContinueWith(t => {
IEnumerable<ParseObject> comments = t.Result;
// Comments now contains the last ten comments, and the "post" field
// contains an object that has already been fetched. For example:
foreach (var comment in comments)
{
// This does not require a network access.
string o= comment.Get<string>("content");
Debug.Log(o);
try {
string post = comment.Get<ParseObject>("parent").Get<string>("title");
Debug.Log(post);
} catch (Exception ex) {
Debug.Log(ex);
}
}
});
It worked!
And then, I have 2 objects: User and Gamescore, in the Gamescore objects have a collumn: "playerName" pointer to Post obj I want join them too:
var query = ParseObject.GetQuery ("GameScore");
query.Include ("playerName");
query.FindAsync ().ContinueWith (t =>{
IEnumerable<ParseObject> result = t.Result;
foreach (var item in result) {
Debug.Log("List score: ");
int score = item.Get<int>("score");
Debug.Log(score);
try {
var obj = item.Get<ParseUser>("playerName");
string name = obj.Get<string>("profile");
//string name = item.Get<ParseUser>("playerName").Get<string>("profile");
Debug.Log(name);
} catch (Exception ex) {
Debug.Log(ex);
}
}
});
but It isn't working, Please help me!
Why didn't you do the following like you did your first example:
query = query.Include ("playerName");
you just have -
query.Include ("playerName");
One solution would be to ensure that your ParseUser object is properly fetched. ie:
var obj = item.Get<ParseUser>("playerName");
Task t = obj.FetchIfNeededAsync();
while (!t.IsCompleted) yield return null;
Then you can do this without worrying:
string name = obj.Get<string>("profile");
But that will be another potential request to Parse, which is unfortunate. It seems that query.Include ("playerName") isn't properly working in the Unity version of Parse?
I believe you're supposed to use multi-level includes for this, like .Include("parent.playerName") in your first query.