-->
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.  [ 14 posts ] 
Author Message
 Post subject: Composite-Id question.
PostPosted: Sun Apr 05, 2009 11:55 pm 
Newbie

Joined: Thu Mar 19, 2009 12:11 am
Posts: 7
There are very few working project examples that I can find online. And none that address my particular issue.

Here is my domain model:

Student:
int ID
IList<Course> Courses

Course:
int ID
IList<Student> Students
IList<Assignment> Assignments

Assignment:
int ID
Course Course
double TotalPoints
double UserPoints

The issue is mapping the assignments to contain the UserPoints unique to a logged in user. Basically I need a seperate table with composite key { Assignment, Student } with a value { UserScore }.

I tried creating a class UserGrade with this mapping:
Code:
<class name="UserGrade" table="UserGrade">
    <composite-id >
      <key-many-to-one name="Assignment" column="AssignmentID" class="Assignment" />
      <key-many-to-one name="User" column="UserID" class="User" />
    </composite-id>
    <property name="Score" type="System.Double">
      <column name="Score" not-null ="false"/>
    </property>
  </class>

The issue is mapping it to my Assignment class. Whatever I try, this is the error I receive:

Quote:
UserGrade.id of: DataTransfer.Assignment, type component[Assignment,User] expects 2 columns, but 1 were mapped


I need to figure out how to map the UserGrade class to be accessed from Assignment. If anyone else know of a better way of doing this without creating a new class, it would be a huge help.


Top
 Profile  
 
 Post subject: Re: Composite-Id question.
PostPosted: Mon Apr 06, 2009 10:11 am 
Regular
Regular

Joined: Wed Feb 11, 2009 10:58 am
Posts: 55
UNoLaugh wrote:
Student:
int ID
IList<Course> Courses

Course:
int ID
IList<Student> Students
IList<Assignment> Assignments

Assignment:
int ID
Course Course
double TotalPoints
double UserPoints


I see no connection from Assignment to User?

Student:
int ID
IList<Course> Courses
IList<Assignment> Assignments

Course:
int ID
IList<Student> Students
IList<Assignment> Assignments

Assignment:
int ID
Course Course
Student Student
double TotalPoints
double UserPoints

If you don't put the Student in the assignment you can just save a list of Assignments, but you don't have the information to which Student the Assignment belongs to.
And you don't need a composite-id for this.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 06, 2009 10:34 am 
Newbie

Joined: Thu Mar 19, 2009 12:11 am
Posts: 7
Many Students are members of Many Courses.

One Course has Many Assignments.

One Assignment has One Grade for Each Student.

However there are Many Grades for One Assignment, unique to Each Student.


The context of the application is from the perspective of one logged in User. So, the one user has a List of Courses, each with a list of Assignments. But, each assignment should only have One grade value of type Double that is unique to the Student logged in.

In other words, many Students share a unique common Assignment that needs unique Grade bound to it per Student.

My goal is to make that relationship as transparent as possible, where the class would look like this:

Assignment:
int ID - shared instance
Course Course - shared instance
double TotalPoints - shared instance
double UserPoints - unique to user (composite-id { Assignment, User } value { double UserPoints })

I hope that explains better the structure I have in my head. It may not be possible to make it as transparent as I would like. This is for my undergrad Sr. project on a team of four, but I am stuck coding all three tiers ( Data, Business Logic, and Presentation). They need it as POCO as possible.

Any suggestions from you all who have more experience would be a life saver at this point.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 06, 2009 10:55 am 
Regular
Regular

Joined: Wed Feb 11, 2009 10:58 am
Posts: 55
so in the Course class you want to show only the Assignments for the logged in User and not all Assignments? Am I right?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 06, 2009 11:02 am 
Newbie

Joined: Thu Mar 19, 2009 12:11 am
Posts: 7
Not quite. If a Student is a member of a Course, he should see all Assignments attached to that Course. However, within the Assignment is a property 'Double UserPoints' that I need to represent a score unique to the Student for the given Assignment.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 06, 2009 11:12 am 
Regular
Regular

Joined: Wed Feb 11, 2009 10:58 am
Posts: 55
maybe I'm blind, but I don't see the problem. If you do it like this

Student:
int ID
IList<Course> Courses
IList<Assignment> Assignments

Assignment:
(int ID )
<composite-key>
Course Course
Student Student
</composite-key>
double UserPoints

Course:
int ID
IList<Student> Students
IList<Assignment> Assignments
double TotalPoints //I think this one is the same for all Assignments in this Course

Every Student Object has only got the Assignments which belong to this User.
In the Course you've got all Assignments for that specific Course.

You could even map it to, if that would be something you need very often:

Student:
int ID
IList<Course> Courses
IDictionary<Course, Assignment> Assignments

Assignment:
int ID
Course Course
Student Student
double UserPoints

Course:
int ID
IList<Student> Students
IDictionary<Student, Assignment> Assignments
double TotalPoints //I think this one is the same for all Assignments in this Course


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 06, 2009 11:51 am 
Newbie

Joined: Thu Mar 19, 2009 12:11 am
Posts: 7
In the case you have laid out, if a course has 300 students, there will be 300 unique Assignments in the database that will store 300 duplicate entries where only 1 double field is different.

The top diagram represents what your mapping will store in the database. The bottom diagram shows what I am trying to accomplish.

Image

The complicating issue is having the EarnedPoints represented in the Assignment POCO as a value property, and not as an instantiated class reference.

Unfortunately I may have to create a UserGrade { Assignment, User, EarnedPoints } with a composite-id of { Assignment, User}. However I tried this approach, and had no clue how to map UserGrade as a value in Assignment. I kept getting an error telling me it was looking for 2 id values but was only provided one.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 06, 2009 12:21 pm 
Regular
Regular

Joined: Wed Feb 11, 2009 10:58 am
Posts: 55
Sorry, I thought an Assignment is a Grade for each User.

Well something like

Student:
int ID
IList<Course> Courses
IDictionary<Assignment, double> Grades

should be possible. You could try:

Code:
<map table="USERGRADES" name="Grades">
  <key column="ID_USER" />
  <index-many-to-many class="Assignment" column="ID_ASSIGNMENT"/>
  <element type="double" column="USER_GRAD" />
</map>


Though I don't know if that will work, because the table has no class assigned, but at least you can give it a try :)

Edit: OK, the table is created even when there is no class assigned to the table. Just give it a shot and tell me if it works :)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 08, 2009 1:19 pm 
Newbie

Joined: Thu Mar 19, 2009 12:11 am
Posts: 7
I implemented your suggested and it does in fact create the table. Unfortunately I cannot figure out how to actually pass values into the table. I found similar implementations of Idictionaries but none of them discuss actually getting data into the table.

Here is an example of the code I am executing in my UnitTest:

Code:
Course course = new Course();
...

User user = new User();
...

Assignment assignment = new Assignment();
  ...
  course.Tasks.Add(assignment);
  session.Save(assignment);

  user.Grades = new Dictionary<Assignment, double>();
  user.Grades.Add(assignment, 96.5);
  session.SaveOrUpdate(user);


The Assignment is pushed to the database, however the grades are not. I even tried adding "IDictionary<User, double>" Grades to Assignment and switching the mappings around to match. No luck.

I know its been a few days, but any suggestions would be great. I may start a new post, since this is starting to veer off course of my initial post.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 08, 2009 3:28 pm 
Regular
Regular

Joined: Wed Feb 11, 2009 10:58 am
Posts: 55
This worked for me.

Code:
<class xmlns="urn:nhibernate-mapping-2.2" name="User" table="HibernateUsers"  >
    <id name="UserId"  column="ID_USER" type="Int32" >
      <generator class="native"/>
    </id>
    <map table="USERGRADES" name="Grades">
      <key column="ID_USER" />
      <index-many-to-many class="Assignment" column="ID_ASSIGNMENT"/>
      <element type="double" column="USER_GRADE" />
    </map>
  </class>


and this c# code:

Code:
Configuration cfg = new Configuration();
cfg.Configure();
cfg.AddAssembly("frmNhibernateTest");
ISessionFactory sf = cfg.BuildSessionFactory();

new SchemaExport(cfg).Create(true, true);
           
session = sf.OpenSession();

User user = new User();
session.Save(user);

Assignment ass = new Assignment();
ass.Name = "Hello World";
session.Save(ass);

user.Grades.Add(ass, 4.5);
session.Save(user);

session.Flush();


Assignment just consists of an Id and a Name for simplicity.

Maybe you should try to save the User Object before adding something to the Dictionary.

I also added the complete SQL statements executed by NHibernate:

Code:
create table HibernateUsers (
  ID_USER INT IDENTITY NOT NULL,
   primary key (ID_USER)
)
create table USERGRADES (
  ID_USER INT not null,
   USER_GRADE DOUBLE PRECISION null,
   ID_ASSIGNMENT INT not null,
   primary key (ID_USER, ID_ASSIGNMENT)
)
create table ASSIGNMENT (
  ID_ASSIGNMENT INT IDENTITY NOT NULL,
   NAME NVARCHAR(255) null,
   primary key (ID_ASSIGNMENT)
)
alter table USERGRADES add constraint FK40D019BBC5BBBBB4 foreign key (ID_USER) references HibernateUsers
alter table USERGRADES add constraint FK40D019BBF3042FE8 foreign key (ID_ASSIGNMENT) references ASSIGNMENT
NHibernate: INSERT INTO HibernateUsers DEFAULT VALUES; select SCOPE_IDENTITY()
NHibernate: INSERT INTO ASSIGNMENT (NAME) VALUES (@p0); select SCOPE_IDENTITY(); @p0 = 'Hello World'
NHibernate: INSERT INTO USERGRADES (ID_USER, ID_ASSIGNMENT, USER_GRADE) VALUES (@p0, @p1, @p2); @p0 = '1', @p1 = '1', @p2 = '4,5'


Last edited by reflection on Wed Apr 08, 2009 3:40 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 08, 2009 3:37 pm 
Newbie

Joined: Thu Mar 19, 2009 12:11 am
Posts: 7
I am an idiot. I was missing session.flush().

Unfortunately I am a rookie and am still using generator="identity" and mistook the initial identifier call as the session flush.

Hopefully we can wrap up the major functional requirements of this project soon and flesh out little things like that.

Thank you so much for you help.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 08, 2009 3:42 pm 
Regular
Regular

Joined: Wed Feb 11, 2009 10:58 am
Posts: 55
lol I thought about that, but that was too obvious :) well at least the problem is solved.

I think generator="identity" is the best way of all. We use an Oracle DB at work, so I use sequences.


Top
 Profile  
 
 Post subject: Re: Composite-Id question.
PostPosted: Sat Jun 12, 2010 3:21 am 
Newbie

Joined: Sat Jun 12, 2010 1:32 am
Posts: 2
hi,
i hava following mapping with a map of Idictionary<Item,int>,while Item is an entity.
<map name="ItemWeightsInForm" table="T_Form_Item">
<key column="FormId"/>
<index-many-to-many column="ItemId" class="Item"/>

<element column="weight" type="int"></element>
</map>

my question is how to access this idictonary using hql.


Top
 Profile  
 
 Post subject: Re:
PostPosted: Sat Jun 12, 2010 3:42 am 
Newbie

Joined: Sat Jun 12, 2010 1:32 am
Posts: 2
reflection wrote:
lol I thought about that, but that was too obvious :) well at least the problem is solved.

I think generator="identity" is the best way of all. We use an Oracle DB at work, so I use sequences.

hi,
i hava following mapping with a map of Idictionary<Item,int>,while Item is an entity.
<map name="ItemWeightsInForm" table="T_Form_Item">
<key column="FormId"/>
<index-many-to-many column="ItemId" class="Item"/>

<element column="weight" type="int"></element>
</map>

my question is how to access this idictonary using hql.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 14 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.