Searching for Attributes with PageEntity

Vote:
 

Hi,

I've just implemented PageEntities described here.
http://world.episerver.com/Blogs/Per-Hemmingson/Dates/2009/6/Do-you-want-Community-features-on-your-CMS-pages-PageEntity-to-the-rescue/

Now I have a problem however. What I have done is made an attribute for the PageEntityType StandardPage of the type IUser called "Subscribers". I want to add subscribers to my StandardPages. Everything works great and the subscribers are added fine to the DB. However, my problem is that I want to search for all the pages that IUser "X" is subscribing to or get all those pages. So I thought I'd use the PageEntityQuery class to search the DB for results. 

public

 

 

static PageEntityCollection GetSubscriptionsStandardPageEntity(IUser user) {

PageEntityQuery
query = new PageEntityQuery();
UserCriterion userCriteria = new UserCriterion();
userCriteria.ID = new IntegerCriterion();
userCriteria.ID.Value = user.ID;
query.PageType = new IntegerCriterion();
query.PageType.Value = 2; //value of the StandardPage PageEntityType

query["Subscribers" = userCriteria;
PageEntityCollection collection = QueryHandler.GetQueryResult<PageEntity, PageEntityCollection>(query);

return
collection;
}

This method will give me an error saying that the attribute "Subscribers" doesn't exist for PageEntity, which is correct. However it does exist for StandardPageEntity. How can I tell the PageEntityQuery that I want to search the StandardPageEntities for "Subscribers" entries with the UserId criterion?

My next step was to create a class called StandardPageQuery which returns results of the type StandardPageEntity. This gave me a TargetInvocationException however which I didn't understand at all. Have anyone successfully searched a PageEntity with the PageEntityQuery class?

Thanks

/Jens

#41011
Jun 28, 2010 15:31
Vote:
 

Anyone got an answer for this? I have started again to try and solve this with no luck.

#44965
Oct 22, 2010 11:21
Vote:
 

I'm having the exact same problem. I've tried only querying after a page entity with it's ID as well, and that throws the target invocation exception.

I've used reflector and some copy/paste and what I think look the most suspect is the "GetQuery" method in QueryBase. When it creates the select command it becomes SELECT FullNamespaceToPageEntity FROM Full.Namespace.To.PageEntity AS FullNamespaceToPageEntity.

Is that the nhibernate wrapping in play? Because it looks very strange to me.

#45362
Nov 04, 2010 15:51
Vote:
 

I managed to solve this today. Doing it the second way, by adding a StandardPageEntityQuery that returns StandardPageEntity (I also created a StandardpageEntityCollection just to be safe). I had tried that before of course and gotten the same error. It still needs to be done to get to the real solution though. Note, the StandardPageEntityQuery should inherit from FrameworkEntityQueryBase not QueryBase (to get attribute querying).

What solved this problem for me was to add nhibernate mappings for the page entities. I did it the xml way (I think it can be done programmatically as well, not sure). Add a folder called mappings to your root (not sure it needs to go there, but that's what the instructions said and I don't want to experiment).

In it add a file called StandardPageEntity.hbm.xml

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="AssemblyName"
                   namespace="Full.Namespace">

  <class name="StandardPageEntity" table="tblPageEntity">
    <id name="PageGUID">
      <column name="pkPageGuid"/>
      <generator class="guid" />
    </id>
    <property name="EntityType" ></property>
    <property name="ID"></property>
  </class>

</hibernate-mapping>
This file needs to have it's build action set to Embedded Resource.   

Then build the project and hopefully it'll work for you.

#45427
Nov 05, 2010 15:46
Vote:
 

I did what you suggested and I put the mappings to Embedded Resource.

<?xml version="1.0" encoding="utf-8" ?>

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"

assembly="AssemblyName"

namespace="Full.Namespace">

<class name="StandardPagePageEntity"

table="tblPageEntity">

<id name="PageGUID">

<column name="pkPageGuid"/>

<generator class="guid" />

</id>

<property name="EntityType" ></property>

<property name="ID"></property>

</class>

</hibernate-mapping>

My name for standardpageentity is StandardPagePageEntity though, but that shouldn't matter right?

Here's my query class for StandardPagePageEntity

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using EPiServer.Common.Queries;

namespace EPiServer.Templates.RelatePlus.Templates.PageEntity
{

public class StandardPageEntityQuery : FrameworkEntityQueryBase
{

public StandardPageEntityQuery() : base(typeof(StandardPagePageEntity))
{

}

}

}

Can you see anything wrong?

#45453
Nov 08, 2010 9:22
Vote:
 

Hmm...should I change the namespace and assembly value in hibernate mapping?

#45454
Nov 08, 2010 9:26
Vote:
 

Yeah, those were dummy values. Assemblyname should be the name of your assembly and namespace should be the full namespace in which the StandardPagePageEntity resides.

And no, the name of the class shouldn't matter.

 

Also, you might need to specify the criterions in your query class (This was done in my PageEntity classes, so I kept it that way). This is my queryclass:

public class StandardPageEntityQuery : FrameworkEntityQueryBase
	{
        /// <summary>
        /// Initializes a new instance of the <see cref="PageEntityQuery"/> class.
        /// </summary>
        public StandardPageEntityQuery()
            : base(typeof(StandardPageEntity))
        {
            this.PageType = new IntegerCriterion();
            this.PageType.Value = (int)PageEntityTypes.Standard;
        }

        /// <summary>
        /// Gets or sets the type of the page.
        /// </summary>
        /// <value>The type of the page.</value>
        protected IntegerCriterion PageType
        {
            get { return base.GetCriterion<IntegerCriterion>("EntityType"); }
            set { base.SetCriterion<IntegerCriterion>("EntityType", value); }
        }


        /// <summary>
        /// Gets or sets the site ID.
        /// </summary>
        /// <value>The site ID.</value>
        public IntegerCriterion SiteID
        {
            get { return base.GetCriterion<IntegerCriterion>("SiteID"); }
            set { base.SetCriterion<IntegerCriterion>("SiteID", value); }
        }
	}
    

    I wrote the query so that it will always look for a page entity with the type I wan, so it won't need to be specified manually. Also, I don't think SiteID is needed, it came with the original code, but as far as I know there is little use for it now.

 

Standard
#45455
Edited, Nov 08, 2010 9:42
Vote:
 

I still get targetInvocationException with this method on the getQueryResult call. I've added everything you said I should. The xml example you posted does your xml look exactly the same with exception from the namespace and assembly?

I want to search a certain users Subscriptions and the exact same query works for blogs and topics so there can't be anything wrong with the way I query, can it?

Jens

public static StandardPageEntityCollection GetSubscriptionsStandardPageEntity(IUser user)

{

StandardPageEntityQuery query = new StandardPageEntityQuery();

UserCriterion userCriteria = new UserCriterion();

userCriteria.ID = new IntegerCriterion();

userCriteria.ID.Value = user.ID;

query["Subscribers"] = userCriteria;

StandardPageEntityCollection collection = QueryHandler.GetQueryResult<StandardPagePageEntity, StandardPageEntityCollection>(query);

return collection;

}

 

#45457
Nov 08, 2010 10:21
Vote:
 

My XML looks exactly like I posted, except for assembly and namespace.

I don't think the query should be the problem, but just to be safe, try querying after just the pageentity type and see if you get results. I did get results when using an attribute though.

A thought, you're querying what seems to be a user collection with a single user, but if it works for blogs, then I don't know.

Also, I'm using Community 4, from your code it looks like you're using 3.x? Don't know if that makes a difference, but it could I suppose.

#45458
Nov 08, 2010 10:35
Vote:
 

I don't know if you figured this out, but I did forget to mention one thing (I forgot I had done it, which backfired when moved to a testing environment).

In web.config, you need to add mapping of the assembly.

Like this:

<hibernate-configuration>
    <session-factory>
        <mapping assembly="Assembly.Name"/>

 

(where Assembly.Name is your assembly name)

hibernate-configuration
<hibernate-configuration>
	<session-factory>
		<mapping assembly="Assembly.Name"/>
    
<hibernate-configuration>
	<session-factory>
		<mapping assembly="Assembly.Name"/>
    
#45626
Nov 11, 2010 10:20
Vote:
 

That moved things forward a bit. A new problem occured though that I cannot understand. Any thoughts or ideas?

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: NHibernate.InvalidProxyTypeException: The following types may not be used as proxies:
EPiServer.Templates.RelatePlus.Templates.PageEntity.NewsPagePageEntity: method get_PageGUID should be virtual
EPiServer.Templates.RelatePlus.Templates.PageEntity.StandardPagePageEntity: type should have a visible (public or protected) no-argument constructor
EPiServer.Templates.RelatePlus.Templates.PageEntity.StandardPagePageEntity: method get_SiteID should be virtual
EPiServer.Templates.RelatePlus.Templates.PageEntity.StandardPagePageEntity: method set_EntityType should be virtual
EPiServer.Templates.RelatePlus.Templates.PageEntity.NewsPagePageEntity: method get_PageLink should be virtual
EPiServer.Templates.RelatePlus.Templates.PageEntity.NewsPagePageEntity: method get_EntityType should be virtual
EPiServer.Templates.RelatePlus.Templates.PageEntity.StandardPagePageEntity: method get_PageGUID should be virtual
EPiServer.Templates.RelatePlus.Templates.PageEntity.NewsPagePageEntity: type should have a visible (public or protected) no-argument constructor
EPiServer.Templates.RelatePlus.Templates.PageEntity.NewsPagePageEntity: method set_EntityType should be virtual
EPiServer.Templates.RelatePlus.Templates.PageEntity.StandardPagePageEntity: method get_EntityType should be virtual
EPiServer.Templates.RelatePlus.Templates.PageEntity.StandardPagePageEntity: method get_PageLink should be virtual
EPiServer.Templates.RelatePlus.Templates.PageEntity.NewsPagePageEntity: method get_SiteID should be virtual
EPiServer.Templates.RelatePlus.Templates.PageEntity.NewsPagePageEntity: method set_SiteID should be virtual
EPiServer.Templates.RelatePlus.Templates.PageEntity.StandardPagePageEntity: method set_SiteID should be virtual

 

#45635
Nov 11, 2010 13:16
Vote:
 

Of course. I had these errors as well (it took a long time to get it to work, so I keep forgetting things). First, the PageEntity properties needs to be changed to virtual (to allow them to be properly overriden, don't know why nhibernate requires this). Ie instead of reading

public PageEntityTypes EntityType { get; set; }

they should read

public virtual PageEntityTypes EntityType { get; set; }

Or similar for the other properties.

Also, your subtype needs a base constructor without arguments. So the classes you add in PageEntity subclasses needs to look something like this:

public class StandardPagePageEntity : PageEntity
    {
        //this is the added part
        public StandardPagePageEntity ()
            : base()
        {
        }
        //added part ends here
        public StandardPagePageEntity (Guid pageGuid)
            : base(pageGuid, PageEntityTypes.BloggSida)
        {
        }
        public StandardPagePageEntity (int id, Guid pageGuid)
            : base(id, pageGuid, PageEntityTypes.BloggSida)
        {
        }
    }
    

Hopefully that'll do it, if you get mroe error messages keep posting and I'll see if I encountered them as well.

#45641
Nov 11, 2010 14:06
Vote:
 

Yes I fixed it exactly the same. I'm struggling with this now. Oh and thank you for taking the time to help me out! :-)

Index was outside the bounds of the array.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.IndexOutOfRangeException: Index was outside the bounds of the array.

Source Error:

Line 72: 
Line 73:             int id = reader.GetInt32(1);
Line 74:             int siteID = reader.GetInt32(3);
Line 75: 
Line 76:             return (PageEntity)Activator.CreateInstance(type, new object[] { id, siteID, pageGuid });


Source File: C:\Documents and Settings\sejp13735\My Documents\Visual Studio 2010\Projects\WSP.Intranet\classes\PageEntity\PageEntityProvider.cs    Line: 74

[IndexOutOfRangeException: Index was outside the bounds of the array.]
   System.Data.SqlClient.SqlDataReader.ReadColumn(Int32 i, Boolean setTimeout) +778886
   System.Data.SqlClient.SqlDataReader.GetInt32(Int32 i) +19
   EPiServer.Common.Data.OffsetDbDataReader.GetInt32(Int32 ordinal) +70
   EPiServer.Templates.RelatePlus.Templates.PageEntity.PageEntityProvider.ConstructPageEntity(Type type, DbDataReader reader) in C:\Documents and Settings\sejp13735\My Documents\Visual Studio 2010\Projects\WSP.Intranet\classes\PageEntity\PageEntityProvider.cs:74
   EPiServer.Templates.RelatePlus.Templates.PageEntity.PageEntityProvider.GetEntityInstance(Type type, DbDataReader reader) in C:\Documents and Settings\sejp13735\My Documents\Visual Studio 2010\Projects\WSP.Intranet\classes\PageEntity\PageEntityProvider.cs:45
   EPiServer.Common.Data.QueryFactory.GetQueryResult(Type entityType, String hql, Object[] parameters, Int32 page, Int32 pageSize) +474

[TargetInvocationException: Exception has been thrown by the target of an invocation.]
   System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner) +0
   System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner) +71
   System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks) +261
   System.Delegate.DynamicInvokeImpl(Object[] args) +84
   System.Delegate.DynamicInvoke(Object[] args) +7
   EPiServer.Common.Cache.CacheHandler.GetCachedObjectImplementation(Delegate cacheObjectGetter, Object[] getterArgs, Nullable`1 cacheTimeSpan, NotFoundInCacheAnnouncer notFoundInCacheAnnouncer, String[] key) +767
   EPiServer.Common.Cache.CacheHandler.GetCachedObject(Delegate cacheObjectGetter, Object[] getterArgs, String[] key) +99
   EPiServer.Common.Queries.QueryHandler.GetQueryResult(IQuery query, Nullable`1 explicitCacheTime, Int32 page, Int32 pageSize, Int32& totalItems) +1911
   EPiServer.Common.Queries.QueryHandler.GetQueryResult(IQuery query, Int32 page, Int32 pageSize, Int32& totalItems) +152
   EPiServer.Common.Queries.QueryHandler.GetQueryResult(IQuery query, Int32 page, Int32 pageSize) +101
   EPiServer.Common.Queries.QueryHandler.GetQueryResult(IQuery query) +96
   EPiServer.Templates.RelatePlus.SubscriptionUtility.GetSubscriptionsStandardPageEntity(IUser user) in C:\Documents and Settings\sejp13735\My Documents\Visual Studio 2010\Projects\WSP.Intranet\Templates\RelatePlus\Utils\SubscriptionUtility.cs:276
   WSPIntranet.Templates.Units.Placeable.SubscriptionFeed.DataBind() in C:\Documents and Settings\sejp13735\My Documents\Visual Studio 2010\Projects\WSP.Intranet\Templates\Units\Placeable\SubscriptionFeed.ascx.cs:29
   WSPIntranet.Templates.Units.Placeable.SubscriptionFeed.Page_Load(Object sender, EventArgs e) in C:\Documents and Settings\sejp13735\My Documents\Visual Studio 2010\Projects\WSP.Intranet\Templates\Units\Placeable\SubscriptionFeed.ascx.cs:21
   System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) +14
   System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +35
   System.Web.UI.Control.OnLoad(EventArgs e) +99
   System.Web.UI.Control.LoadRecursive() +50
   System.Web.UI.Control.LoadRecursive() +141
   System.Web.UI.Control.LoadRecursive() +141
   System.Web.UI.Control.LoadRecursive() +141
   System.Web.UI.Control.LoadRecursive() +141
   System.Web.UI.Control.LoadRecursive() +141
   System.Web.UI.Control.LoadRecursive() +141
   System.Web.UI.Control.LoadRecursive() +141
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +627

#45643
Nov 11, 2010 14:23
Vote:
 

hmm, gonna try to add property SiteID to the mapping. Seems it get three columns and

int siteID = reader.GetInt32(3);

...looks in a fourth.

#45644
Nov 11, 2010 14:26
Vote:
 

YES!! That solved it! WOHOO!

I now have users subscriptions connected to news, standard pages, topics and blogs via attributes! :-) So happy at the moment! Thank you so much for your help!

#45645
Nov 11, 2010 14:34
Vote:
 

You're very welcome. Glad it worked out for you.

:)

#45646
Nov 11, 2010 14:41
This thread is locked and should be used for reference only. Please use the Legacy add-ons forum to open new discussions.
* 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.