views:

240

answers:

1

I'm using Fluent NHibernate to create an ASP.NET MVC project, with Submissions and Votes (Up/Down) by Users.

Of course, Users can vote submission Up or Down. To record this, I created a middle table, SubmissionVote, which contain the following fields:

submissionId (int)
userId (int)
score (enum: up/down)

Here are my mappings:

Submission

Id(x => x.Id);
...
References(x => x.User).Column("userID").Not.LazyLoad();
HasMany(x => x.Votes).Cascade.All().KeyColumn("submissionID").Table("SubmissionVote").Not.LazyLoad();
Table("Submission");

User

Id(x => x.Id);
...
HasMany(x => x.Submission).Inverse().KeyColumn("userID").Cascade.All();
HasMany(x => x.SubmissionVotes).KeyColumn("userID").Cascade.All().Table("SubmissionVote");

SubmissionVote

Map(x => x.Vote).Column("score");
CompositeId().KeyProperty(x => x.Submission.Id, "submissionID").KeyProperty(x => x.User.Id, "userID");
References(x => x.Submission).Column("submissionID");
References(x => x.User).Column("userID");

Since the middle table in my DB has a score field, I created the SubmissionVote class the represent it. The user and submission fields in that class are many-to-one relationships to their respective classes.

The problem is this: the SubmissionVote class need to have an ID property, otherwise NHibernate produces an error. That should not be the case, since the ID for a SubmissionVote is a composite-id, as represented in the mapping.

I can live with, but it causes another problem. When I try to save a submission with a few SubmissionVotes in it, using session.SaveOrUpdate(submission), I get this error a ArrayOutOfBounds exception thrown by MySQL, like in this question: http://stackoverflow.com/questions/1203078/how-can-i-use-a-composite-id-with-a-class-as-the-id-field-in-fluent-nhibernate.

Looking at the NHibernate logs, I can see the query that is sent to MySQL.

14:53:07.358 [9] DEBUG ... - Building an IDbCommand object for the SqlString: INSERT INTO `SubmissionVote` (score, submissionID, userID) VALUES (?, ?, ?)
14:53:07.361 [9] DEBUG ... - binding 'Up' to parameter: 0
14:53:07.367 [9] DEBUG NHibernate.Type.Int32Type - binding '183' to parameter: 1
14:53:07.367 [9] DEBUG NHibernate.Engine.IdentifierValue - unsaved-value: 0
14:53:07.367 [9] DEBUG NHibernate.Type.Int32Type - binding '2' to parameter: 2
14:53:07.367 [9] DEBUG NHibernate.Type.Int32Type - binding '0' to parameter: 3

Apparently, NHibernate tries to include a default "ID" value ('0') to the query (probably the ID property I added to the SubmissionVote).

Are the two problems related? How can I solve this problem?

Thank you very much!

Edit

Here is my (partial, but relevent) schema produced by NHibernate.

create table submission (
    Id INTEGER NOT NULL AUTO_INCREMENT,
   CreationDate DATETIME,
   BeginDate DATETIME,
   EndDate DATETIME,
   Content VARCHAR(255),
   userID INTEGER,
   primary key (Id)
)

create table User (
Id INTEGER NOT NULL AUTO_INCREMENT,
   UserName VARCHAR(255) unique,
   Password VARCHAR(255),
   Email VARCHAR(255),
   primary key (Id)
)

create table `submissionVote` (
submissionID INTEGER not null,
   userID INTEGER not null,
   score VARCHAR(255),
   primary key (submissionID, userID)
)

alter table `submissionVote` 
    add index (submissionID), 
    add constraint FKC2AE73C56C66D2D5 
foreign key (submissionID) 
references submission (Id)

alter table `submissionVote` 
add index (userID), 
add constraint FKC2AE73C5EC6C1277 
foreign key (userID) 
references User (Id)

alter table submission 
 add index (userID), 
 add constraint FKE6354599EC6C1277 
 foreign key (userID) 
 references User (Id)
+3  A: 

I found the solution! Actually, I had to specify to NHibernate that the composite-id also happens to be my references.

The new mappings looks like this:

Map(x => x.Vote).Column("score");
CompositeId().KeyReference(x => x.Submission, "submissionID").KeyReference(x => x.User, "userID");
Guillaume Gervais