none
Problem following links using NHibernate and Data Services

    Question

  • I am using NHibernate for my persistence model and want to expose it through a Data Service. I'm using NHibernate.LINQ and NHibernate 2.1. I've created a data context object derived from NHibernateContext and created my data service. The application is a simple blog-type application.

    I have a Post object that has a child relationship with a Comment object. I can browse to either the comments or the posts successfully from my data service, but when I try to follow the relationship, I am getting the following exception:

    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
      <code></code>
      <message xml:lang="en-US">An error occurred while processing this request.</message>
      <innererror>
        <message>resourceType must be a type assignable to resourceSet.</message>
        <type>System.ArgumentException</type>
        <stacktrace>   at System.Data.Services.Providers.ResourceAssociationSetEnd..ctor(ResourceSet resourceSet, ResourceType resourceType, ResourceProperty resourceProperty)&#xD;
       at System.Data.Services.Providers.ReflectionServiceProvider.GetResourceAssociationSet(ResourceSet resourceSet, ResourceType resourceType, ResourceProperty resourceProperty)&#xD;
       at System.Data.Services.Providers.DataServiceProviderWrapper.GetResourceAssociationSet(ResourceSetWrapper resourceSet, ResourceType resourceType, ResourceProperty resourceProperty)&#xD;
       at System.Data.Services.Providers.DataServiceProviderWrapper.GetResourceProperties(ResourceSetWrapper resourceSet, ResourceType resourceType)&#xD;
       at System.Data.Services.Serializers.SyndicationSerializer.WriteObjectProperties(IExpandedResult expanded, Object customObject, ResourceType resourceType, Uri absoluteUri, String relativeUri, SyndicationItem item, DictionaryContent content, EpmSourcePathSegment currentSourceRoot)&#xD;
       at System.Data.Services.Serializers.SyndicationSerializer.WriteEntryElement(IExpandedResult expanded, Object element, ResourceType expectedType, Uri absoluteUri, String relativeUri, SyndicationItem target)&#xD;
       at System.Data.Services.Serializers.SyndicationSerializer.WriteTopLevelElement(IExpandedResult expanded, Object element)&#xD;
       at System.Data.Services.Serializers.Serializer.WriteRequest(IEnumerator queryResults, Boolean hasMoved)&#xD;
       at System.Data.Services.ResponseBodyWriter.Write(Stream stream)</stacktrace>
      </innererror>
    </error>

    Basically, my code looks like this:

    [DataServiceKey("Id")]
    public class Comment
    {
        ...
        public virtual int Id { get; set; }
        public virtual Post Post { get; set; }
        ...
    }

    [DataServiceKey("Id")]
    public class Post
    {
        ...
        public virtual IList<Comment> Comments { get; private set; }
        public virtual int Id { get; set; }
        ...
    }

    public class BlogContext : NHibernateContext
    {
        public IOrderedQueryable<Comment> Comments
        {
            get
            {
                return this.Session.Linq<Comment>();
            }
        }

        public IOrderedQueryable<Post> Posts
        {
            get
            {
                return this.Session.Linq<Post>();
            }
        }
    }

    public class BlogDataService : DataService<BlogContext> { ... }

    I can run queries such as the following:

    http://localhost:5000/BlogDataService.svc
    http://localhost:5000/BlogDataService.svc/Posts
    http://localhost:5000/BlogDataService.svc/Posts(1)
    http://localhost:5000/BlogDataService.svc/Comments
    http://localhost:5000/BlogDataService.svc/Comments(1)

    Those all work. But when I try to navigate a relationship, I get the exception:

    http://localhost:5000/BlogDataService.svc/Posts(1)/Comments
    http://localhost:5000/BlogDataService.svc/Comments(1)/Post

    Any help with understanding why I am getting this would be greatly appreciated.

    Thanks.

    Michael 
    Monday, December 28, 2009 7:26 PM

Answers

  • Hi,

    I must say right now I'm suspecting NHibernate to be cause this problem. The metadata generated from your classes is correct. No problem there. Actually all the variable values you posted are also correct except for the resourceType being "Post", that should be "Comment".
    I've seen some problems with NHibernate LINQ implementation already. Just out of curiosity - what happens if you run this query:
    BlogDataService.svc/Posts?$expand=Comments

    I think that will work. In which case I've seen this problem already. It's caused by the Posts(123) which turns into a Where LINQ operator in the query and NHibernate seems to have problems with the Where returning bogus results (I don't know why).

    Thanks,
    Vitek Karas [MSFT]
    Thursday, January 07, 2010 4:37 PM
    Moderator

All replies

  • Hello Michael,

     

    Welcome to MSDN Forums!

     

    I am not quite familiar with LINQ to NHibernate.  However, to make the relationship work, we need to let the model implements the IUpdatable interface.  Here are some references about how to implement it for NHibernate model in ADO.NET Data Services:

    http://wildermuth.com/2008/07/20/Silverlight_2_NHibernate_LINQ_==_Sweet

    http://wildermuth.com/2008/07/21/NHibernate_LINQ_with_ADO_NET_Data_Services

    http://ayende.com/Blog/archive/2008/07/21/ADO.Net-Data-Services-with-NHibernate.aspx

     

     

    Happy New Year, Michael!

     

    Best Regards,
    Lingzhi Sun

    MSDN Subscriber Support in Forum

    If you have any feedback on our support, please contact msdnmg@microsoft.com


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Tuesday, December 29, 2009 7:56 AM
    Moderator
  • Hello Michael,

     

    I am writing to check the status of the issue on your side.  Would you mind letting me know the result of the suggestions? 

     

    If you need further assistance, please feel free to let me know.   I will be more than happy to be of assistance.

     

    Have a nice day!

     

     

    Best Regards,
    Lingzhi Sun

    MSDN Subscriber Support in Forum

    If you have any feedback on our support, please contact msdnmg@microsoft.com


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Monday, January 04, 2010 12:56 AM
    Moderator
  • Hi,

    I tried your classes from above in a simple reflection provider (no NHibernate as that only comes into play when executing the LINQ query) but it works for me just fine. Note that sometimes even a small thing can cause the requests to fail. Given the exception above, it means that some of the metadata is wrong. Could you try running the http:/.../BlogDataService.svc/$metadata request and see if that fails?
    You could also try to attach a debugger to the service and stop on any exception being thrown. Then look at the local variables in th emethod which throws the exception, you might see which resource type and resource set are causing the problem.

    Thanks,
    Vitek Karas [MSFT]
    Monday, January 04, 2010 10:25 AM
    Moderator
  • Sorry for the delay. Client going into production and experiencing all of the fun of that process...

    I tried the $metadata call and that worked. The metadata looks correct.

    I turned on exception breakpoints as you suggested and got the exception again when I tried to follow the relationship. When I run BlogDataService.svc, I get the list of entities, which is correct. When I run BlogDataService.svc/Blogs, I get the list of blogs. When I run BlogDataService.svc/Blogs(4) I get the specific blog. If I run BlogDataService.svc/Blogs(4)/Posts, I get the exception.

    Again, the exception is reporting "resourceType must be a type assignable to resourceSet" in the constructor for ResourceAssociationSetEnd. The resourceSet property is a System.Data.Services.Providers.ResourceSetWrapper object for "Posts." The resourceType parameter is a System.Data.Services.Providers.ResourceType object for "Blog." Everything looks ok with the properties inside of them. They have the correct number of parameters, etc. The only thing of interest that I see is that the debugger is showing in the local window that the AllEmpInfo property for both resourceSet and resourceType evaluates to "resourceType.AllempInfo threw and exception of type System.NullReferenceException."

    Thursday, January 07, 2010 1:47 PM
  • Hi,

    This is weird. The variable values you posted are wrong (so the exception is correct), the resource set "Posts" can't have resources of resource type "Blog" in it, that's why it's failing. The question is how did that happen.
    Just to verify the last parameter to the constructor called resourceProperty is null right?
    Please verify that the code you poasted earlier is truly the code you're running. Especially the classes themselves (do they inherit from something else, do they inherit from each other...). And also the types of IQueryable<T> you return.
    While in the debugger, you can go up one frame to the ReflectionServiceProvider.GetResourceAssociationSet and take a loot at variables resourceSet, resourceType and resourceProperty. Especially the resourceProperty. What is the value of resourceProperty.ResourceType?
    I assume that it should that resourceProperty.Name is Posts and resourceProperty.ResourceType should be "Post", but from the values you posted it will probably say resourceProperty.ResourceType is "Blog".

    In your sample above you posted classes Comment and Post, could you please post the classes you use now (Post and Blog)?

    Also since you do get $metadata working, can you post the response to it as well?

    Thanks,

    Vitek Karas [MSFT]
    Thursday, January 07, 2010 3:12 PM
    Moderator
  • Could this be because I have bi-directional associations between my entities. On my Blog class, I have a collection called Posts of Post objects. On my post class, I have a Blog property that points back to the original Blog object, such that BlogDataService.svc/Blogs(4)/Posts(1)/Blog would point back to the same object that you'd get with BlogDataService.svc/Blogs(4)?
    Thursday, January 07, 2010 3:15 PM
  • Sorry...my bad on the example. Too early in the morning and I wasn't thinking when I switched to the Blog<-->Posts relationship.

    Going back to the previous example with Posts and Comments, when I use BlogDataService.svc/Posts(135)/Comments, I get the ArgumentException "resourceType must be a type assignable to resourceSet." The resourceSet parameter is a ResourceSetWrapper object for "Comments." The resourceType parameter is a ResourceType object for "Post." The last parameter, resourceProperty, is a ResourceProperty object with Kind = ResourceSetReference and Name = "Authors." Authors is another relationship from Post. The resourceProperty.ResourceType is set to "Author"/EntityType.

    Here's the classes (only relationships, not data properties):

    public class Blog {
        public virtual IList<Post> Posts { get; private set; }
    }

    public class Post {
        public virtual IList<Author> Authors { get; private set; }
        public virtual Blog Blog { get; set; }
        public virtual IList<Category> Categories { get; private set; }
        public virtual IList<Comment> Comments { get; private set; }
        public virtual IList<Tag> Tags { get; private set; }
    }

    public class Author {
        public virtual IList<Post> Posts { get; private set; }
    }

    public class Category {
        public virtual IList<Post> Posts { get; private set; }
    }

    public class Comment {
        public virtual Post Post { get; set; }
    }

    public class Tag {
        public virtual IList<Post> Posts { get; private set; }
    }

    The metadata is too big to post in this message. I put it at http://media.imaginaryrealities.com.s3.amazonaws.com/metadata.xml.
    Thursday, January 07, 2010 4:07 PM
  • Forgot to show the BlogContext class that my DataService is based on. Here it is:

    namespace ImaginaryRealities.Website.Web
    {
        using System;
        using System.Linq;
        using NHibernate;
        using NHibernate.Linq;

        [CLSCompliant(false)]
        public class BlogContext : NHibernateContext
        {
            public BlogContext()
            {
            }

            public BlogContext(ISession session) : base(session)
            {
            }

            public IQueryable<Author> Authors
            {
                get
                {
                    return this.Session.Linq<Author>();
                }
            }

            public IQueryable<Blog> Blogs
            {
                get
                {
                    return this.Session.Linq<Blog>();
                }
            }

            public IQueryable<Category> Categories
            {
                get
                {
                    return this.Session.Linq<Category>();
                }
            }

            public IQueryable<Comment> Comments
            {
                get
                {
                    return this.Session.Linq<Comment>();
                }
            }

            public IQueryable<Post> Posts
            {
                get
                {
                    return this.Session.Linq<Post>();
                }
            }

            public IQueryable<Tag> Tags
            {
                get
                {
                    return this.Session.Linq<Tag>();
                }
            }
        }
    }

    Thursday, January 07, 2010 4:09 PM
  • Hi,

    I must say right now I'm suspecting NHibernate to be cause this problem. The metadata generated from your classes is correct. No problem there. Actually all the variable values you posted are also correct except for the resourceType being "Post", that should be "Comment".
    I've seen some problems with NHibernate LINQ implementation already. Just out of curiosity - what happens if you run this query:
    BlogDataService.svc/Posts?$expand=Comments

    I think that will work. In which case I've seen this problem already. It's caused by the Posts(123) which turns into a Where LINQ operator in the query and NHibernate seems to have problems with the Where returning bogus results (I don't know why).

    Thanks,
    Vitek Karas [MSFT]
    Thursday, January 07, 2010 4:37 PM
    Moderator
  • You're correct. The $expand did work. I have the NHibernate and NHibernate.Linq source code. I'll work through it from there to see if I can get an answer, or look into switching to LINQ to SQL or EF.

    Thank you very much for your assistance.
    Thursday, January 07, 2010 4:58 PM
  • You're correct. The $expand did work. I have the NHibernate and NHibernate.Linq source code. I'll work through it from there to see if I can get an answer, or look into switching to LINQ to SQL or EF.

    Did you manage to find anything in the end?  I'm having a similar problem -- using http://localhost/MyService/X and http://localhost/MyService/Y lists things correctly, as does http://localhost/MyService/X(1)?$expand=Y, but http://localhost/MyService/X(1)/Y produces garbage (the result is formatted as if it was type X, not type Y).
    Tuesday, July 13, 2010 1:15 AM
  • You're correct. The $expand did work. 

    I was also interested on the status of this.  I can get BlogDataService.svc/Posts?$expand=Comments to work, but a query with a _specific_ Posts and it fails for me.  For ex. ,  BlogDataService.svc/Posts(23) ?$expand=Comments  will fail.

     

    I am thinking using NHibernate and WCF Data Services is not a good ideal right now.  It does not seem to be stable.

    Friday, August 20, 2010 1:52 PM