Filter multiple types

Vote:
 

Hi,

How can I filter over multiple types. For example I've got two different Types: A and B, both with a string property with two different names. How can I filter on both types to select only the objects with the string property value starting with the letter C?

In the documentation it's clear how to search in two different types with the method IncludeType, but how can I use this method with specific type filters?

 

Thanks

#75122
Sep 18, 2013 11:46
Vote:
 

Anyone?

#75234
Sep 23, 2013 8:22
Vote:
 

Hi Patrick,

This, specifically the second to last code example, should help you.

#75242
Sep 23, 2013 14:50
Vote:
 

Hi Joel,


This is what I'm trying to do:

_client.Search<UserDto>()
                   .Filter(
                       r =>
                       (r.FirstName.Prefix(filter.SearchLetter)) |
                       (r.MatchType(typeof(BasePage)) & ((BasePage)r).PageName.Prefix(filter.SearchLetter)))

The code above won't compile, because I can't cast a BasePage to a UserDto object. Is there another solution for this?

Thanks.

#75254
Edited, Sep 23, 2013 19:44
Vote:
 

Hmm, that should compile although it may produce a warning about a conspicious cast. What exactly does the compiler say?

Given that you do get it to compile you probably want to do like below instead given that we're using &/| rather than &&/||:

(!r.MatchType(typeof(BasePage)) | ((BasePage)r).PageName.Prefix(filter.SearchLetter))

#75255
Sep 23, 2013 19:52
Vote:
 

I'm getting two errors:

- Cannot convert lambda expression to type 'EPiServer.Find.Api.Querying.Filter' because it is not a delegate type

- Cannot convert type 'UserDto' to 'BasePage'

#75256
Sep 23, 2013 19:56
Vote:
 

Regarding the "convert type" error you cannot cast your reference type  in c# to another type if it isn't a basetype or a derived type, i.e there is no way for a UserDto object to be a BasePage.

To fix this you could either inherit BasePage from UserDto (or vice versa if it makes sense), or use:

client.search<BasePage>().
.Filter().
.Select(x => new UserDto { p1 = x.p1 ... })

to make the conversion yourself.

Regards,

Henrik

#75269
Sep 24, 2013 8:51
Vote:
 

So it isn't possible to filter on two types if they haven't have the same basetype?

#75270
Sep 24, 2013 9:02
Vote:
 

It is, but you need to either:

a) use unified search

or

b) find a way to get the compiler out of your way

In order to do b) you can instead search for Object and add filters that require objects to be either UserDto or BasePage and then apply the rest of your filters. Alternatively, I think you should be able to to ((BasePage)((Object)x)).PageName.Prefix... Nasty looking, yes :)

#75271
Sep 24, 2013 9:10
Vote:
 

Great, thanks! I managed to get it working with the Object type. Now I've the following:

result = result.Filter(r => (r.MatchType(typeof (UserDto)) & ((UserDto) r).FirstName.Prefix(filter.SearchLetter)));
                result = result.OrFilter(r => (r.MatchTypeHierarchy(typeof(BaseLocationPage)) & ((BaseLocationPage)r).PageName.Prefix(filter.SearchLetter)));

var query = result.Take(1000);

query.GetResult();

    

The only this is that if get the result, only the properties of the type BaseLocationPage are filled, the properties of the basetype PageData are all empty?

#75277
Sep 24, 2013 11:26
Vote:
 

Hmm, could you paste the full code?

To simplify things (potentially A LOT), would it be an option to have both classes implement a common interface?

#75278
Sep 24, 2013 11:29
Vote:
 
/// <summary>
        /// Search user in index
        /// </summary>
        /// <returns></returns>
        public IEnumerable<Object> SearchUserInIndex_1(SearchUsersFilter filter)
        {
            var list = new List<WhoWhatWhereSearchResult>();

            var result = _client.Search<Object>();

            if (!string.IsNullOrEmpty(filter.Criteria))
            {
                var searchResult = result.For(filter.Criteria);
                if (filter.SearchCollegue || filter.SearchExpertise)
                {
                    result.Filter(r => r.MatchTypeHierarchy(typeof(UserDto)));
                }
                if (filter.SearchLocations)
                {
                    result.Filter(r => r.MatchTypeHierarchy(typeof (BaseLocationPage)));
                }

                result = searchResult;
            }

            if (filter.SortByFirstName)
                result = result.OrderBy(u => (u is UserDto ? ((UserDto)u).FirstName : ((BaseLocationPage)u).PageName));
            else if (filter.SortByLastname)
                result = result.OrderBy(u => (u is UserDto ? ((UserDto)u).LastName : ((BaseLocationPage)u).PageName));

            if (!string.IsNullOrEmpty(filter.SearchLetter))
            {
                result = result.Filter(r => (r.MatchType(typeof (UserDto)) & ((UserDto) r).FirstName.Prefix(filter.SearchLetter)));
                result = result.OrFilter(r => (r.MatchTypeHierarchy(typeof(BaseLocationPage)) & ((BaseLocationPage)r).PageName.Prefix(filter.SearchLetter)));
            }

            var query = result.Take(1000);

            int totalNumberOfUsers;
            var batch = query.GetResult();

            foreach (var page in batch.ToList())
            {
                list.Add(GetSearchResultItem(page));
            }

            totalNumberOfUsers = batch.TotalMatching;

            var nextBatchFrom = 1000;
            while (nextBatchFrom < totalNumberOfUsers)
            {
                batch = query.Skip(nextBatchFrom).GetResult();
                foreach (var page in batch.ToList())
                {
                    list.Add(GetSearchResultItem(page));
                }
                nextBatchFrom += 1000;
            }
            return list;
        }

    

/// <summary>
        /// Get search result item
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        private WhoWhatWhereSearchResult GetSearchResultItem(Object obj)
        {
            if (obj is UserDto)
                return WhoWhatWhereSearchResult.FromUserDto((UserDto) obj);
            else if (obj is BaseLocationPage)
                return WhoWhatWhereSearchResult.FromLocation((BaseLocationPage)obj);
            
            return new WhoWhatWhereSearchResult();
        }
public class WhoWhatWhereSearchResult
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public UserDto User { get; set; }
        public BaseLocationPage Location { get; set; }

        public static WhoWhatWhereSearchResult FromUserDto(UserDto user)
        {
            var item = new WhoWhatWhereSearchResult
                {
                 Id = user.Id,
                 Name = user.DisplayName,
                 User = user
                };
            return item;
        }

        public static WhoWhatWhereSearchResult FromLocation(BaseLocationPage page)
        {
            var item = new WhoWhatWhereSearchResult
            {
                Id = page.PageLink.ID,
                Name = page.PageName,
                Location = page
            };
            return item;
        }
    }

    

#75280
Edited, Sep 24, 2013 11:33
Vote:
 

Would you mind posting the code for the GetSearchResultItem method as well?

#75281
Sep 24, 2013 11:35
Vote:
 

Done

#75282
Sep 24, 2013 11:36
Vote:
 

Thanks.

What's strange is that you're actually getting anything back instead of an exception. Typically you can't retrieve full PageData objects from the index as they are hard to deserialize. Instead we get them by ID (well, PageReference). Anyway, two (more) questions:

1. Is the data you use from WhoWhatWhereSearchResult.User and from WhoWhatWhereSearchResult.Location limited? What I'm getting at is; are you only using a limited number of properties from the UserDto and PageData objects or do you truly need the full objects?

2. Is there an API method somewhere in your application to get a UserDto by ID, and if so, is it fast/cached?

#75283
Sep 24, 2013 11:46
Vote:
 

No I'm not using all of the data, only a few properties (3 of User and 1 of Location)  that I need in my view.


Yes there is an API method where I can retrieve a UserDto by ID and it is being cached.

#75284
Sep 24, 2013 11:49
Vote:
 

Cool, then I'd say you have two viable options to choose from:

A) Use the Select method to retrieve only UserId and PageLink.ID from the index and pass both to a method that retrieves the original objects from either your user API or from EPiServer's API. It would look something like this:

query.Select(x => GetResultObject(((UserDto)x).User.Id, ((PageData)x).PageLink.ID).GetResult();

...

private static Object GetResultObject(int? userId, int? pageId)
{
  if(userId.HasValue)
  {
    return myHappyUserApi.GetById(userId.Value);
  }
  if(pageId.HasValue)
  {
    return DataFactory.Instance.Get<BaseLocationPage>(new PageReference(pageId.Value));
  }

  throw new Exception("Something is wrong, we need to look at what we're getting back");
}

    

B) Create an interface containing all the data that you need, both in terms of what you want to filter on and what you want to retrieve. Make both UserDto and BaseLocationPage implement the interface. Create a class that contains the data that you need to retrieve from the index. Search for your interface and then add a projection (using the Select method) where you project from the interface to your result class.

Personally I'd opt for B) but A) is probably quicker to implement.

#75285
Sep 24, 2013 12:00
Vote:
 

The problem with solution A is that ((PageData)x).PageLink.ID is empty for some reason, only the properties of the type BaseLocationPage are filled not of the basetype PageData? I think the best thing to do is to implement a common interface.

Thanks for your help!

#75286
Sep 24, 2013 12:12
Vote:
 

Can you filter out pages who's parent page is not a certain pageType. Basically, in the main site search I dont want to show pages who's Parent is a Member PageType.

Thanks

Jon

#131969
Aug 11, 2015 11:36
Vote:
 

See answer in the following post: http://world.episerver.com/forum/developer-forum/-EPiServer-75-CMS/Thread-Container/2015/8/filter-out-parent-pages-by-pagetype/

#131976
Aug 11, 2015 14:26
This topic was created over six months ago and has been resolved. If you have a similar question, please create a new topic and refer to this one.
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.