Fetching projection of expanded entity in OData

554 views
Skip to first unread message

Vagif Abilov

unread,
May 9, 2011, 9:47:10 AM5/9/11
to nhu...@googlegroups.com
Hi,

After resolving my issue with navigation to referenced entities (thanks Ricardo), I am now testing possibility to fetch in OData only referenced entities. The following query fetches main entity and it's Products relation:
Categories.Expand("Products").Where(c => c.CategoryID == 1)
(corresponds to http://localhost:50555/NorthwindEntityFrameworkModelFirstMsSql.svc/Categories(1)?$expand=Products)

This is not what I want: I only need Products. I don't want to do projection on the client.

When using Entity Framework, I can use the following (weird) C# syntax in client code:
from c in Categories.Where(c => c.CategoryID == 1) select new { Products = c.Products }

But this does not work in NHibernate! I am getting NotImplemented exception:

<message xml:lang="nb-NO">Not Implemented</message>
  <innererror>
    <message>([100001] As Categories)</message>
    <type>System.NotSupportedException</type>
...
</message>

And using Expand("Products") does not seem to support projections: Categories.Expand("Products").Where(c => c.CategoryID == 1).Select(x => x.Products) results in "The method 'Select' is not supported." both for NHibernate and Entity Framework.

Do you know about any workaround for this that will work in NHibernate?

Thanks in advance

Vagif

Ricardo Peres

unread,
May 9, 2011, 12:07:50 PM5/9/11
to nhusers
WCF Data Services supports projections (server-side, not client-side,
this you can always do with LINQ to Objects), but you have to enable
them:

public static void InitializeService(DataServiceConfiguration config)
{
config.DataServiceBehavior.MaxProtocolVersion =
DataServiceProtocolVersion.V2;
config.DataServiceBehavior.AcceptProjectionRequests = true;
...
}

Also, I wrote a post on WCF Data Services debugging, a long time ago:
http://weblogs.asp.net/ricardoperes/archive/2009/11/01/debugging-ado-net-data-services.aspx

RP

On May 9, 2:47 pm, Vagif Abilov <vagif.abi...@gmail.com> wrote:
> Hi,
>
> After resolving my issue with navigation to referenced entities (thanks
> Ricardo), I am now testing possibility to fetch in OData only referenced
> entities. The following query fetches main entity and it's Products
> relation:
> Categories.Expand("Products").Where(c => c.CategoryID == 1)
> (corresponds tohttp://localhost:50555/NorthwindEntityFrameworkModelFirstMsSql.svc/Ca...
> )

Vagif Abilov

unread,
May 9, 2011, 5:31:45 PM5/9/11
to nhu...@googlegroups.com
Hi Ricardo,

Projection is enabled in my service and if I use Entity Framework instead of NH, the following query works fine:

Categories.Where(x => x.CategoryID == 1).SelectMany(x => x.Products)

But NH returns me the following error:

<message>element.Products is not mapped [.SelectMany[Northwind.NHibernate.MsSql.Categories,Northwind.NHibernate.MsSql.Products](.Where[Northwind.NHibernate.MsSql.Categories](NHibernate.Linq.NhQueryable`1[Northwind.NHibernate.MsSql.Categories], Quote((element, ) =&gt; (Equal(element.CategoryID, p1))), ), Quote((element, ) =&gt; (Convert(element.Products))), )]</message>
<type>NHibernate.Hql.Ast.ANTLR.QuerySyntaxException</type>

What I can do is to issue other query that works:
Categories.Expand("Products").Where(x => x.CategoryID == 1)

But this one does not project Products, it just includes them in the result set. So I wonder if DataService needs more tweaking for NHibernate to correctly handle projection.

Vagif



--
You received this message because you are subscribed to the Google Groups "nhusers" group.
To post to this group, send email to nhu...@googlegroups.com.
To unsubscribe from this group, send email to nhusers+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/nhusers?hl=en.


Vagif Abilov

unread,
May 9, 2011, 5:44:29 PM5/9/11
to nhu...@googlegroups.com
... and if I execute the same query

context.Categories.Where(x => x.CategoryID == 1).SelectMany(x => x.Products)

using NH directly (not via OData service), it works fine. The error happens only if send the query through WCF Data Service, and only if I use NHibernate. With EF this is not a problem.

Vagif

Ricardo Peres

unread,
May 10, 2011, 4:43:28 AM5/10/11
to nhusers
How are you creating the session/context? Are you using the
DataService<T>.CreateDataSource() method?


On May 9, 10:44 pm, Vagif Abilov <vagif.abi...@gmail.com> wrote:
> ... and if I execute the same query
>
> context.Categories.Where(x => x.CategoryID == 1).SelectMany(x => x.Products)
>
> using NH directly (not via OData service), it works fine. The error happens
> only if send the query through WCF Data Service, and only if I use
> NHibernate. With EF this is not a problem.
>
> Vagif
>
> On Mon, May 9, 2011 at 11:31 PM, Vagif Abilov <vagif.abi...@gmail.com>wrote:
>
>
>
>
>
>
>
> > Hi Ricardo,
>
> > Projection is enabled in my service and if I use Entity Framework instead
> > of NH, the following query works fine:
>
> > Categories.Where(x => x.CategoryID == 1).SelectMany(x => x.Products)
>
> > But NH returns me the following error:
>
> > <message>element.Products is not mapped
> > [.SelectMany[Northwind.NHibernate.MsSql.Categories,Northwind.NHibernate.MsS ql.Products](.Where[Northwind.NHibernate.MsSql.Categories](NHibernate.Linq. NhQueryable`1[Northwind.NHibernate.MsSql.Categories],
> > Quote((element, ) =&gt; (Equal(element.CategoryID, p1))), ), Quote((element,
> > ) =&gt; (Convert(element.Products))), )]</message>
> > <type>NHibernate.Hql.Ast.ANTLR.QuerySyntaxException</type>
>
> > What I can do is to issue other query that works:
> > Categories.Expand("Products").Where(x => x.CategoryID == 1)
>
> > But this one does not project Products, it just includes them in the result
> > set. So I wonder if DataService needs more tweaking for NHibernate to
> > correctly handle projection.
>
> > Vagif
>
> > On Mon, May 9, 2011 at 6:07 PM, Ricardo Peres <rjpe...@gmail.com> wrote:
>
> >> WCF Data Services supports projections (server-side, not client-side,
> >> this you can always do with LINQ to Objects), but you have to enable
> >> them:
>
> >> public static void InitializeService(DataServiceConfiguration config)
> >> {
> >>    config.DataServiceBehavior.MaxProtocolVersion =
> >> DataServiceProtocolVersion.V2;
> >>    config.DataServiceBehavior.AcceptProjectionRequests = true;
> >>    ...
> >> }
>
> >> Also, I wrote a post on WCF Data Services debugging, a long time ago:
>
> >>http://weblogs.asp.net/ricardoperes/archive/2009/11/01/debugging-ado-...

Vagif Abilov

unread,
May 10, 2011, 4:55:01 AM5/10/11
to nhu...@googlegroups.com
Here is what I do:

1. Define entities (some code skipped for clarity):
    [DataServiceKey("CategoryID")]
    public class Categories
    {
        public virtual int CategoryID { get; set; }
        public virtual ICollection<Products> Products { get; set; }
        /**/
    }
    public class CategoriesMap : ClassMap<Categories>
    {
        public CategoriesMap()
        {
            Id(x => x.CategoryID).GeneratedBy.Increment();
            HasMany(x => x.Products)
                .Table("Products")
                .KeyColumn("CategoryID");
            /**/
        }
    }

    [DataServiceKey("ProductID")]
    public class Products
    {
        public virtual int ProductID { get; set; }
        public virtual int CategoryID { get; set; }
        public virtual Categories Category { get; set; }
        /**/
    }
    public class ProductsMap : ClassMap<Products>
    {
        public ProductsMap()
        {
            Id(x => x.ProductID);
            Map(x => x.CategoryID);
            References(x => x.Category).Not.LazyLoad()
                .Column("CategoryID");
            /**/
        }
    }

2. Define context
    public class NorthwindContext : NHibernateDataContext
    {
        public NorthwindContext(ISession session) : base(session) { }
        public IQueryable<Categories> Categories
        {
            get { return new NhQueryable<Categories>(base.Session.As<ISessionImplementor>()); }
        }
        public IQueryable<Products> Products
        {
            get { return new NhQueryable<Products>(base.Session.As<ISessionImplementor>()); }
        }
        /**/
        public static ISessionFactory CreateSessionFactory(string connectionString)
        {
            return Fluently.Configure()
                .Database(MsSqlConfiguration.MsSql2008
                .ConnectionString(connectionString)
                .Cache(c => c
                    .UseQueryCache()
                    .ProviderClass<HashtableCacheProvider>())
                .ShowSql())
                .Mappings(m => m.FluentMappings.AddFromAssemblyOf<NorthwindContext>())
                .BuildSessionFactory();
        }
    }


So far so good. All tests work.

3. Now I implement an OData service:

    [ServiceBehavior(IncludeExceptionDetailInFaults = true)]
    public class NHibernateMsSql : DataService<NorthwindContext>, IDisposable
    {
        private ISession session;

        public void Dispose()
        {
            if (this.session != null)
            {
                this.session.Dispose();
                this.session = null;

            }
        }

        public static void InitializeService(DataServiceConfiguration config)
        {
            config.SetEntitySetAccessRule("*", EntitySetRights.All);
            config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
            config.DataServiceBehavior.AcceptCountRequests = true;
            config.DataServiceBehavior.AcceptProjectionRequests = true;
            config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
            config.UseVerboseErrors = true;
        }

        protected override void HandleException(HandleExceptionArgs args)
        {
            base.HandleException(args);
            Elmah.ErrorLog.GetDefault(null).Log(new Error(args.Exception));
        }

        protected override NorthwindContext CreateDataSource()
        {
            var factory = NorthwindContext.CreateSessionFactory(
                ConfigurationManager.ConnectionStrings["NorthwindContext.NH.MsSql"].ConnectionString);

            this.session = factory.OpenSession();
            this.session.FlushMode = FlushMode.Auto;

            return new NorthwindContext(this.session);
        }

Then it works fine for non-projection queries but fails as soon as I call SelectMany on it.

Vagif

Ricardo Peres

unread,
Jun 22, 2012, 9:54:40 AM6/22/12
to nhu...@googlegroups.com
Does your context implement IExpandProvider?

On Friday, June 22, 2012 1:51:36 PM UTC+1, João Ferreira wrote:
Hi

I am having the same problem. Have you solved it somehow? Has a bug been reported?

Regards

Alexander Kot

unread,
Jun 25, 2012, 1:09:16 PM6/25/12
to nhu...@googlegroups.com
Hello all

Please vote for this one...
https://nhibernate.jira.com/browse/NH-2463
Reply all
Reply to author
Forward
0 new messages