-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 
Author Message
 Post subject: Table with composite key +LINQ-to-NH = Invalid SQL generated
PostPosted: Tue Jan 11, 2011 1:28 pm 
Newbie

Joined: Tue Jan 11, 2011 11:50 am
Posts: 1
Hi, users of the NHibernate

There is an SQL Server 2005 legacy database and application using it. I'm trying to migrate existing data-access layer to NHibernate. I'm using NHibernate v3.0 with my mappings declared via Fluent NH. Having a couple of POCOs with mappings declared, I tried to run a query using LINQ-to-NH,
Code:
var orders = session.Query<Order>().Where(o => o.Reships.Any(r => r.Reason.IsBillable));

and get a weird error.

NHibernate.Exceptions.GenericADOException : could not execute query
System.Data.SqlClient.SqlException : Incorrect syntax near ','.


Details are below.

Database structure
Actually database has a large amount of tables, but only three are relevant in current discussion.

Table "Order"
Code:
table Order
(
   OrderID bigint PK not null,
   ClientOrderID varchar(255) null,
   ...
   Status, ShippingInfo, PaymentInfo, and couple of other columns, we will not look at them as they are irrelevant in current discussion
   ...
   }
)

Table "Order_reshipment" have composite primary key which composed of both old and new order IDs.
Code:
table Order_reshipment
(
      SourceOrderID bigint not null PK,
      TargetOrderID bigint not null PK,
      ReshipReasonID int null FK references ReshipReason(ReasonID),
)

Table "Reship_reason"
Code:
table Reship_reason
(
    ReasonID int not null PK,
    Name varchar(512) not null,
    IsReshipBillable bit not null
)

Domain Problem Explained
Few words about what are those table for.
User of a system can place an order. When order is placed for the first time, row in table Order is inserted and that is it. If placed order has not been shipped to the customer after all, user may ask for the reship. When reship is fulfilled, new row is inserted in table Order. Also row in table Order_reshipment is inserted to bind the new order and the old one. Order reshipment refers to reship reason via ReshipReasonID foreign key. Reship reason is specified by user.

POCO and mappings
Entity "Order" and mapping.
Code:
public class Order
{
     public Order()
     {}

     public virtual long OrderID { get; private set; }
     ...
     public virtual IList<Reship> Reships { get; private set; }
}

public class OrderMap : ClassMap<Order>
{
     public OrderMap()
     {
     Table("`Order`");
          Id(o => o.OrderID);
          HasMany(o => o.Reships).KeyColumn("TargetOrderID").Inverse().Cascade.All();
     }
}

Entity "Reship" and mapping
Code:
public class Reship
{
      public virtual ReshipIdentifier ID { get; set; }
      public virtual ReshipReason Reason { get; set; }
}

Here we have a composite key mapped as a separate class, having key columns mapped as entity references to parent order (old one) and child order(new one).
Code:
[Serializable]
public class ReshipIdentifier
{
       public Order ChildOrder { get; private set; }
       public Order ParentOrder { get; private set; }
}

Mapping is as follows:
Code:
public class ReshipMap : ClassMap<Reship>
{
   public ReshipMap()
   {
      Table("Order_resubmitted");

      CompositeId(r => r.ID)
        .KeyReference(rid => rid.ChildOrder, k => k.ForeignKey("FK_Order_resubmitted_TargetOrder_OrderID"), "TargetOrderID")
        .KeyReference(rid => rid.ParentOrder, k => k.ForeignKey("FK_Order_resubmitted_SourceOrder_OrderID"), "SourceOrderID");

       References(r => r.Reason).ForeignKey("FK_Order_resubmitted_Reship_reason_ReasonID");
    }
}

Entity "ReshipReason" and mapping
Code:
public class ReshipReason
{
      public virtual int ReasonID { get; private set; }
      public virtual string Name { get; set; }
      public virtual bool IsBillable { get; set; }
}

public class ReshipReasonMap : ClassMap<ReshipReason>
{
     public ReshipReasonMap()
     {
          Id(r => r.ReasonID).Column("ReasonID");
          Map(r => r.Name).Not.Nullable().Column("ReasonName");
          Map(r => r.IsBillable).Not.Nullable().Column("IsReshipBillable");
      }
}


Query and Fail
So, having all this code, I'm trying to get orders which were created as a result of reship operation, and were reshipped with billable reason. I'm using LINQ, which have out of box support in version 3.0 of the NHibernate.
Code:
var orders = session.Query<Order>().Where(o => o.Reships.Any(r => r.Reason.IsBillable));

Very simple query, isn't it? However it does not work at all. Let's have a look on SQL generated by the query.
Code:
select
    order0_.OrderID as OrderID4_,
    order0_.ExternalOrderID as External2_4_,
    ...
from [Order] order0_
where exists(
    select
        (reships1_.TargetOrderID,
        reships1_.SourceOrderID)
    from
        Order_resubmitted reships1_,
        Reship_reason reshipreas2_
    where
        order0_.OrderID=reships1_.TargetOrderID
        and reships1_.ReasonID=reshipreas2_.ReasonID
        and reshipreas2_.IsReshipBillable=1
)

If you run it you will get and error with message: "Incorrect syntax near ','."
The problem is the brackets in these lines of code.
Code:
...
select
        (reships1_.TargetOrderID,
        reships1_.SourceOrderID)
    from
...

NHibernate selects the key of Reship entity (Order_reshipment table) in the subquery in where clause. The key is composite, thus two columns are selected. But those columns are embraced in brackets. This is actually the error reason. With brackets removed, query is executed successfully.

I cannot realize why NHibernate composes SQL statements in that way. Very strange behavior. Can anyone help me to figure out what is the reason? Maybe something wrong with my code, or maybe this is as designed, or may there is a bug in NH?

Waiting for your help.


Top
 Profile  
 
 Post subject: Re: Table with composite key +LINQ-to-NH = Invalid SQL generated
PostPosted: Thu Mar 10, 2011 3:08 pm 
Newbie

Joined: Thu Mar 10, 2011 3:06 pm
Posts: 1
Just ran into this same issue. Did you figure out any work arounds?

Edit
Found this bug report which seems to match:
http://216.121.112.228/browse/NH-2280


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.