views:

58

answers:

2

Hi all,

I'm currently building a web application with MVC and NHibernate. Now when i want to get information out of the database I get an index was out of range exception.

The current situation is as follows.

I got the mapping files of three database tables:
A table to store a group with a one-to-many relationship with subscriberingroup.

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <joined-subclass name="CMS.Business.Entities.Subscriber, CMS.Business.Entities" extends="CMS.Business.Entities.BaseEntity, CMS.Business.Entities" table="CMS_Subscriber">
    <key column="Id" />
    <property name="Email" />
    <property name="FirstName" />
    <property name="Lastname" />
    <list name="SubscriberInGroup" cascade="all" table="CMS_SubscriberInGroup">
      <key column="SubscriberId" />
      <index column="Ordinal" />
      <one-to-many class="CMS.Business.Entities.SubscriberInGroup, CMS.Business.Entities" />
    </list>
  </joined-subclass>
</hibernate-mapping>  

A table to store a subscriber with a one-to-many relationship with subscriberingroup.

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <joined-subclass name="CMS.Business.Entities.Group, CMS.Business.Entities" extends="CMS.Business.Entities.BaseEntity, CMS.Business.Entities" table="CMS_Group">
    <key column="Id" />
    <property name="Name" />
    <list name="SubscriberInGroup" cascade="all" lazy="false" table="CMS_SubscriberInGroup">
      <key column="GroupId" />
      <index column="Ordinal" />
      <one-to-many class="CMS.Business.Entities.SubscriberInGroup, CMS.Business.Entities" />
    </list>
  </joined-subclass>
</hibernate-mapping>   

and last the subscriberingroup mapping

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
    <joined-subclass name="CMS.Business.Entities.SubscriberInGroup, CMS.Business.Entities" extends="CMS.Business.Entities.BaseEntity, CMS.Business.Entities" table="CMS_SubscriberInGroup">
        <key column="Id" />
        <property name="ConfirmationDate" />
        <property name="ConfirmationIP" />
        <property name="SubscribeDate" />
        <property name="SubscribeIP" />
        <property name="SubscribeLocation" />
        <property name="UnSubscribeDate" />
        <property name="UnSubscribeIP" />
        <property name="UnSubscribeLocation" />
        <many-to-one name="Subscriber" class="CMS.Business.Entities.Subscriber, CMS.Business.Entities" column="SubscriberId" />
        <many-to-one name="Group" class="CMS.Business.Entities.Group, CMS.Business.Entities" column="GroupId" />
    </joined-subclass>
</hibernate-mapping>

In the subscriber class I have the following property for the one-to-many relation:

/// <summary>
        /// The subscriberingroup where the subscriber is registered.
        /// </summary>
        [List(4, Name = "SubscriberInGroup", Cascade = CascadeStyle.All)]
        [NHibernate.Mapping.Attributes.Key(5, Column = "SubscriberId")]
        [Index(6, Column = "Ordinal")]
        [OneToMany(7, ClassType = typeof(SubscriberInGroup))]
        public virtual IList<SubscriberInGroup> SubscriberInGroup { get; set; }

In the group class I have the following property for the one-to-manu relation:

/// <summary>
        /// The subscribers of this group.
        /// </summary>
        [List(4, Name = "SubscriberInGroup", Cascade = CascadeStyle.All)]
        [Key(5, Column = "GroupId")]
        [Index(6, Column = "Ordinal")]
        [OneToMany(7, ClassType = typeof(SubscriberInGroup))]
        public virtual IList<SubscriberInGroup> SubscriberInGroup { get; set; }

And in the SubscriberInGroup class I have the following for the many-to-one relation:

/// <summary>
        /// The subscriber.
        /// </summary>
        [ManyToOne(8, ClassType = typeof(Subscriber), Column="SubscriberId", ForeignKey = "FK_Subscriber_SubscriberInGroup")]
        public virtual Subscriber Subscriber { get; set; }
        /// <summary>
        /// The group which is subscribed to.
        /// </summary>
        [ManyToOne(9, ClassType = typeof(Group), Column = "GroupId", ForeignKey = "FK_Group_SubscriberInGroup")]
        public virtual Group Group { get; set; }

When I want to get the SubscriberInGroup with certain values in the group and subscriber table i get an index out of range exception.

This happens with the following query:

SubscriberService.GetSubscriberInGroup(viewModel.EmailAddress, new Guid(s));
                    SubscriberService.GetSubcribersInGroup().Where(
                        g => g.Subscriber.Email == viewModel.EmailAddress && g.Group.Id.ToString().Equals(s1)).
                        FirstOrDefault();

When executing this query I got the exception. The strange thing is when I do this:

var list = SubscriberService.GetSubcribersInGroup().ToList();
                var subscriberInGroup =
                    list.FirstOrDefault(
                        g => g.Subscriber.Email.Equals(viewModel.EmailAddress) && g.Group.Id == new Guid(s1));

it works like i expected too. The GetSubscriberInGroup method looks like this:

public IQueryable GetSubcribersInGroup() { return _session.Linq(); }

I would like it to work like in the first method because the table can contain many entries and ToList() is not an option. So if anyone has any idea why I get this error and how I get it to work properly please share your knowledge!

EDIT:

Below is the stack trace:

 at System.SZArrayHelper.get_Item[T](Int32 index)
   at NHibernate.Linq.Visitors.EntityExpressionVisitor.VisitMethodCall(MethodCallExpression expr)
   at NHibernate.Linq.Visitors.ExpressionVisitor.Visit(Expression exp)
   at NHibernate.Linq.Visitors.EntityExpressionVisitor.FindEntity(Expression expr, Boolean findFirst)
   at NHibernate.Linq.Visitors.BinaryCriterionVisitor.VisitMethodCall(MethodCallExpression expr)
   at NHibernate.Linq.Visitors.ExpressionVisitor.Visit(Expression exp)
   at NHibernate.Linq.Visitors.BinaryCriterionVisitor.GetBinaryCriteria(ICriteria rootCriteria, ISession session, BinaryExpression expr, ComparePropToValue comparePropToValue, ComparePropToProp comparePropToProp, CompareValueToCriteria compareValueToCriteria, ComparePropToCriteria comparePropToCriteria)
   at NHibernate.Linq.Visitors.WhereArgumentsVisitor.VisitBinaryCriterionExpression(BinaryExpression expr)
   at NHibernate.Linq.Visitors.WhereArgumentsVisitor.VisitBinary(BinaryExpression expr)
   at NHibernate.Linq.Visitors.ExpressionVisitor.Visit(Expression exp)

Thanks,

Gerard

A: 

linq-to-nhibernate has to translate your Linq expression to SQL. With that in mind

g.Group.Id.ToString().Equals(s1)

looks problematic. linq-to-nhibernate would have to have the ability to generate sql that converts a Group.Id to a String and compare it to another String... whereas in your working example

g.Group.Id == new Guid(s1)

linq-to-nhibernate only has to generate sql to compare two guids.

On Ayende's blog post talking about linq-to-nhibernate Zoltan Hubai left a comment where he was getting an exception similar to yours with code:

where d.Name.ToLower().StartsWith("a") 

and Ayende's response was:

``I don't think that we support "d.Name.ToLower().StartsWith("a")" at the moment.''

Handcraftsman
Thanks for the response. I already tried to change that line so that the s1 is a Guid in my linq statement and it didn't make any difference.
Gerard
+1  A: 

In one of your mappings i see you're using an ordinal. Is this used for sorting your subcribers in a certain group? Make sure it has the correct value and the values are updated in the right way in the database. For example, if you only have 2 records and your ordinal starts at 10 you'll most likely get this error because a list with 9 empty (nullable) items will be returned. When executing an where condition an exception will be thrown.

edit: Just wondering why you want to order subscribers in a group of something.. If it's not really necessary you could try using a bag. This doesn't require the presence of the ordinal column

Rob
That I didn't think of that! There where rows with ordinals starting at 3 instead of 0... I also changed the list to a bag and deleted the ordinal column. This solved my problem! Thank.
Gerard