Classes required for an application

G

Guest

I am trying to build a rating engine for a number of users for a list of
songs. I havea database design with a user table and a song table and a link
table such that each user can rate many songs and each song can be rated by
many users.

However I am a little stuck on the class design. I hope that this is the
correct place to post such a question and that someone can help with an
answer.

Simply put each rating has a user and a song, which leads me to three classes

class Rating
{
Song song;
User user;
}

class Song{}
class User{}


This is the point at which I am slightly confused if I have a rating object
then I can refer to the song by rating.song and the same for the user.
However If I just want to list all of the ratings for a song, then I really
need the Song object to be composed of a list of ratings in something of a
circular relationship.

Whilst this seems to be supported in c#, it does seem to be risky if a
rating has a song, but the song does not include that rating within the list
of ratings.

Is there another way to build these classes, or is the only way to describe
the relationship between a rating, a user and a song and between a song or
user and it's ratings?

I would be grateful for any assistance. I am very confused about this, so
apologies if my question is confusing.

Richard
 
K

Kevin Spencer

Your Song and User classes are just fine. However, your Rating class is the
problem. A Rating doesn't have a song; a song has a rating, or it may have
many ratings. Again, a Rating doesn't have a User, and neither does a User
have a rating. A rating may have a reference to a number of users, but these
are not users; they might only be User IDs from the database, so that you
can fetch information for any user if your requirements dictate that. The
other part of the rating is not a song, but a score. Does that help?

--
HTH,

Kevin Spencer
Microsoft MVP

Printing Components, Email Components,
FTP Client Classes, Enhanced Data Controls, much more.
DSI PrintManager, Miradyne Component Libraries:
http://www.miradyne.net
 
P

PS

richB said:
I am trying to build a rating engine for a number of users for a list of
songs. I havea database design with a user table and a song table and a
link
table such that each user can rate many songs and each song can be rated
by
many users.

However I am a little stuck on the class design. I hope that this is the
correct place to post such a question and that someone can help with an
answer.

Simply put each rating has a user and a song, which leads me to three
classes

class Rating
{
Song song;
User user;
}

class Song{}
class User{}


This is the point at which I am slightly confused if I have a rating
object
then I can refer to the song by rating.song and the same for the user.
However If I just want to list all of the ratings for a song, then I
really
need the Song object to be composed of a list of ratings in something of a
circular relationship.

Relationships can be circular. A man has a father that has children, one of
which is the the man.
Whilst this seems to be supported in c#, it does seem to be risky if a
rating has a song, but the song does not include that rating within the
list
of ratings.

If a rating has a song then the ratings for that song will include that
rating. I don't see what is "risky"? Are you talking about a data integrity
issue?
Is there another way to build these classes, or is the only way to
describe
the relationship between a rating, a user and a song and between a song or
user and it's ratings?
I would be grateful for any assistance. I am very confused about this, so
apologies if my question is confusing.

I would start with this:

class Rating
{
Song song;
User user;
int Rate;
}

class Song
{
List<Rating> Ratings
}
class User
{
List<Rating> Ratings
}

PS
 
P

PS

Kevin Spencer said:
Your Song and User classes are just fine. However, your Rating class is
the problem. A Rating doesn't have a song;

If a rating doesn't have a song then what was being rated?

a song has a rating, or it may have
many ratings. Again, a Rating doesn't have a User,

so who did the rating?
and neither does a User have a rating.

Finally, I agree on this one
A rating may have a reference to a number of users, but these are not
users

I have no comment on this!!!!
 
R

RichB

Thanks, Your statement that a song has ratings makes sense, though I am not
sure if I just include user ids how I would display (e.g.) the user name
with each rating. Why not have the relationship that Song has many Ratings,
and rating has a User as then if I needed to include anoth user attribute in
my presentation, (e.g.)the user postcode, I would not need to make a change
to my rating class, just use the existing postcode from the user class?

From this model however I can get Songs, their Ratings and the corresponding
User (note there can only be one user per rating as aswell as score there is
revew text).

But there is no way to get Users and their corresponding Songs. In my mind I
can only navigate down the class structure Song.Rating[x].User not start
from User and navigate back to the corresponding Songs without complex
looping through all of the Songs. I may be missing something fundamental
here, but I would have thought that this was a pretty common problem.

Thanks, Richard
 
P

Paul Hadfield

Your Song and User classes are just fine. However, your Rating class is
If a rating doesn't have a song then what was being rated?

a song has a rating, or it may have

so who did the rating?

I'd say I probably use to fall into this trap too and would have agreed with
you, however a rating is just that. A song might have an average rating,
which is from "many" users. An album may have a rating, which is from many
songs. So having the entity classes containing the relationships will only
cause problems in the future and for maintainance.

At that point it's probably best to have "Rating" collection classes. So
you'd have a Song "rating" collection, which contained a reference to a song
and all the ratings (including the average). A user rating collection class
would contain a reference to a user and all the songs they had rated (and
their rating) and so on.

- Paul
 
R

RichB

If a rating has a song then the ratings for that song will include that
rating. I don't see what is "risky"? Are you talking about a data
integrity issue?

Yes the risk is that when creating the objects both the List<rating> and the
rating.song need to be populated at the same time to ensure the data
integrity. It would seem that this is extra work that shouldn't be required.
Iif you just model the heirarchical relationship one way, then on the face
of it, you can derive that the father is the son's father and the son is the
father's son. However in practice I only know of how to navigate from the
parent to the child (father.son), not for child to parent.

Richard
 
P

Paul Hadfield

However in practice I only know of how to navigate from the parent to the
But a father could be a son and a son a father - otherwise evolution
wouldn't have got very far! You have people, then you have relationships,
similar to my other post, keep them separate and when required, using a
containing class to allow navigation.

Person
{
string name;
}

Relationship
{
RelationshipEnumType;
Person1;
Person2;
}

PersonRelationships
{
Person;
Relationship[];
}
 
R

RichB

Thanks, I get what you are saying. I thought that you were talking about 2
people's relationship(father to son and son to father), but you are in fact
talking about 3 people (Grandfather, Father and son). You example structure
does however have one anomally, in the PersonRelationships class you have
person, but in relationship you have two people, though surely you are
expressing a relaionship between Relationship.Person and another person, so
only one person is required in the Relationship class.

I need to think about how this applies to my requirements as my
relationships are between different classes not the same class of object as
in this case. If I apply this to my Songs, Users and Ratings, then I have:

Song
{
string artist;
etc
}

User
{
string name;
etc
}

Rating
{
Song song;
User user;
}

SongUserRatings
{
Rating[] ratings;
}

This way I can simply loop through all SongUserRatings by ratings.song or
ratings.user in order to show corresponding ratings by users for songs or
ratings for songs by users.It still requires looping through the
SogUserRatings, rather than accessing the User from the Song and Song from
the user, but it does make sense to me.

I would appreciate it however if anyone has any further comments on any
other viable approaches.

Thanks, Richard

Paul Hadfield said:
But a father could be a son and a son a father - otherwise evolution
wouldn't have got very far! You have people, then you have relationships,
similar to my other post, keep them separate and when required, using a
containing class to allow navigation.

Person
{
string name;
}

Relationship
{
RelationshipEnumType;
Person1;
Person2;
}

PersonRelationships
{
Person;
Relationship[];
}




RichB said:
Yes the risk is that when creating the objects both the List<rating> and
the rating.song need to be populated at the same time to ensure the data
integrity. It would seem that this is extra work that shouldn't be
required. Iif you just model the heirarchical relationship one way, then
on the face of it, you can derive that the father is the son's father and
the son is the father's son. However in practice I only know of how to
navigate from the parent to the child (father.son), not for child to
parent.

Richard
 
K

Kevin Spencer

Hi Paul,

I agree that a Rating class is probably a good idea, but the idea that it
must have a collection of Users, or a Song property. Since a rating belongs
only to one song, while there is a link in the database, there doesn't have
to be a reverse link in the class structure. That is, a song may have a
Rating assigned to it, which is fetched from the database, but that Rating
doesn't need a song member, because it is already a member of the song. In
fact, it doesn't need a collection of Users either, because a User is not a
class for rating, but with a more general purpose, and a User is not highly
likely to be using a collection of Ratings to view or browse a set of Users.
Instead, the most likely scenario is that the Ratings will be averaged, and
used for statistical purposes. So, a reference to a unique identifier for
each User is likely to be sufficient, so that User data can be fetched in
the unlikely scenario that a rating might be used to obtain User
information.

--
HTH,

Kevin Spencer
Microsoft MVP

Printing Components, Email Components,
FTP Client Classes, Enhanced Data Controls, much more.
DSI PrintManager, Miradyne Component Libraries:
http://www.miradyne.net
 
K

Kevin Spencer

Hi Rich,

I only discussed Ratings in my previous message. Yes, a User should have a
collection of Songs, according to your requirement. It is important, when
working with a database back-end, to analyse the architecture of the
database as a database, and your business objects as business objects. A
database has relationships for the purpose of normalization, so that data
doesn't need to be stored redundantly. A set of business classes, on the
other hand, exists to process and manipulate data, and to enforce business
rules. So, you have to think differently when designing one or the other.
The database is just a storage mechanism, while the business classes
represent process that uses the data. In many cases, business architecture
and database architecture are similar, but one does not dictate the
structure of the other.

If we think of Users, Songs, and Ratings as business entities rather than
database (table) entitites , we can define them in terms of what they do. A
Song is a commodity, something used by Users. A Rating or a collection of
Ratings is part of the Song, or belongs to a Song. A User is a consumer of
Songs. So, a User will perhaps have a Collection of Songs, but the
Collection is not redundant. The Songs are commonly used by many Users, a
pool, if you will, or a global Collection. Each User may have Songs in
his/her Collection that are also used by other Users.

Now, the chain of dependency in this case runs in one direction only: Users
have Songs, which have Ratings. While Songs may be shared, Ratings are not
Shared. Each individual Rating is wholly owned by the song it was created to
rate. Furthermore, we need to think about the purpose of Users, Songs, and
Ratings. A User is a multi-purpose entity which provides an interface for a
person to interact with the application, interact with other Users
(perhaps), and interact with other business entities in the application. A
Song is a commodity that is employed by Users. A User is active, while a
Song is passive. A Rating is a commodity that is employed by Users as well,
but it is tied to a single Song. It is also passive.

The real "trick" here is how the passive Songs can be collected separately
into each User's Songs collection. But if they are in a pool, and each User
has a Collection of references to Songs in the pool, there is still only one
instance of each Song. The Collection is a Collection of references to
Songs, not copies of Songs. Since a class is a reference type, the pool is
actually a Collection of references as well, but its purpose is to collect
all Songs into a single Collection. When a user adds a Song to his/her
Collection, he/she is simply adding another reference, not adding a Song to
anything. Similarly, when the User removes a Song from his/her Collection,
he/she is not deleting the Song, but removing the reference to the song from
the Collection of references.

When a Song instance is created, for example, by a User uploading it, it is
added to the pool. It is the pool that is used to manage the actual Songs,
not the Users who consume them. Again, when it is removed or deleted, it is
deleted from the pool.

A Rating, on the other hand, is a single instance that belongs to a Song,
and is a member of the Song's Ratings Collection. But since the purpose of
the Rating is statistical, and used for the most part in simply getting the
Rating Score for a Song, rather than a handle to a User, it isn't necessary
to add a Collection of User references to the Ratings Collection, although
it could be done.

--
HTH,

Kevin Spencer
Microsoft MVP

Printing Components, Email Components,
FTP Client Classes, Enhanced Data Controls, much more.
DSI PrintManager, Miradyne Component Libraries:
http://www.miradyne.net

RichB said:
Thanks, Your statement that a song has ratings makes sense, though I am
not sure if I just include user ids how I would display (e.g.) the user
name with each rating. Why not have the relationship that Song has many
Ratings, and rating has a User as then if I needed to include anoth user
attribute in my presentation, (e.g.)the user postcode, I would not need to
make a change to my rating class, just use the existing postcode from the
user class?

From this model however I can get Songs, their Ratings and the
corresponding User (note there can only be one user per rating as aswell
as score there is revew text).

But there is no way to get Users and their corresponding Songs. In my mind
I can only navigate down the class structure Song.Rating[x].User not start
from User and navigate back to the corresponding Songs without complex
looping through all of the Songs. I may be missing something fundamental
here, but I would have thought that this was a pretty common problem.

Thanks, Richard



Kevin Spencer said:
Your Song and User classes are just fine. However, your Rating class is
the problem. A Rating doesn't have a song; a song has a rating, or it may
have many ratings. Again, a Rating doesn't have a User, and neither does
a User have a rating. A rating may have a reference to a number of users,
but these are not users; they might only be User IDs from the database,
so that you can fetch information for any user if your requirements
dictate that. The other part of the rating is not a song, but a score.
Does that help?

--
HTH,

Kevin Spencer
Microsoft MVP

Printing Components, Email Components,
FTP Client Classes, Enhanced Data Controls, much more.
DSI PrintManager, Miradyne Component Libraries:
http://www.miradyne.net
 
R

RichB

Kevin,
Thanks, I think that there is some misunderstanding of the relationship
between songs, ratings and users. If we look at this just as a database of
song information and the ratings that users apply to those songs, which can
be desrcribed by a user making a rating for a song. With many users making
ratings for many songs. Which really translates to user has a list of
ratings and each rating is for one song. Each rating will only ever be
related to one user and one song.

I am fairly happy with the structure that I posted in response to comments
from Paul Hadfield:

Song
{
string artist;
etc
}

User
{
string name;
etc
}

Rating
{
Song song;
User user;
}

SongUserRatings
{
Rating[] ratings;
}

(I note now that I missed including the score in the Rating object)

I am reasonable happy that this will meet my requirements, although I am
slightly concerned by the looping that I shall have to do to identify all
ratings for each song or user.

Thanks, Richard


Kevin Spencer said:
Hi Rich,

I only discussed Ratings in my previous message. Yes, a User should have a
collection of Songs, according to your requirement. It is important, when
working with a database back-end, to analyse the architecture of the
database as a database, and your business objects as business objects. A
database has relationships for the purpose of normalization, so that data
doesn't need to be stored redundantly. A set of business classes, on the
other hand, exists to process and manipulate data, and to enforce business
rules. So, you have to think differently when designing one or the other.
The database is just a storage mechanism, while the business classes
represent process that uses the data. In many cases, business architecture
and database architecture are similar, but one does not dictate the
structure of the other.

If we think of Users, Songs, and Ratings as business entities rather than
database (table) entitites , we can define them in terms of what they do.
A Song is a commodity, something used by Users. A Rating or a collection
of Ratings is part of the Song, or belongs to a Song. A User is a consumer
of Songs. So, a User will perhaps have a Collection of Songs, but the
Collection is not redundant. The Songs are commonly used by many Users, a
pool, if you will, or a global Collection. Each User may have Songs in
his/her Collection that are also used by other Users.

Now, the chain of dependency in this case runs in one direction only:
Users have Songs, which have Ratings. While Songs may be shared, Ratings
are not Shared. Each individual Rating is wholly owned by the song it was
created to rate. Furthermore, we need to think about the purpose of Users,
Songs, and Ratings. A User is a multi-purpose entity which provides an
interface for a person to interact with the application, interact with
other Users (perhaps), and interact with other business entities in the
application. A Song is a commodity that is employed by Users. A User is
active, while a Song is passive. A Rating is a commodity that is employed
by Users as well, but it is tied to a single Song. It is also passive.

The real "trick" here is how the passive Songs can be collected separately
into each User's Songs collection. But if they are in a pool, and each
User has a Collection of references to Songs in the pool, there is still
only one instance of each Song. The Collection is a Collection of
references to Songs, not copies of Songs. Since a class is a reference
type, the pool is actually a Collection of references as well, but its
purpose is to collect all Songs into a single Collection. When a user adds
a Song to his/her Collection, he/she is simply adding another reference,
not adding a Song to anything. Similarly, when the User removes a Song
from his/her Collection, he/she is not deleting the Song, but removing the
reference to the song from the Collection of references.

When a Song instance is created, for example, by a User uploading it, it
is added to the pool. It is the pool that is used to manage the actual
Songs, not the Users who consume them. Again, when it is removed or
deleted, it is deleted from the pool.

A Rating, on the other hand, is a single instance that belongs to a Song,
and is a member of the Song's Ratings Collection. But since the purpose of
the Rating is statistical, and used for the most part in simply getting
the Rating Score for a Song, rather than a handle to a User, it isn't
necessary to add a Collection of User references to the Ratings
Collection, although it could be done.

--
HTH,

Kevin Spencer
Microsoft MVP

Printing Components, Email Components,
FTP Client Classes, Enhanced Data Controls, much more.
DSI PrintManager, Miradyne Component Libraries:
http://www.miradyne.net

RichB said:
Thanks, Your statement that a song has ratings makes sense, though I am
not sure if I just include user ids how I would display (e.g.) the user
name with each rating. Why not have the relationship that Song has many
Ratings, and rating has a User as then if I needed to include anoth user
attribute in my presentation, (e.g.)the user postcode, I would not need
to make a change to my rating class, just use the existing postcode from
the user class?

From this model however I can get Songs, their Ratings and the
corresponding User (note there can only be one user per rating as aswell
as score there is revew text).

But there is no way to get Users and their corresponding Songs. In my
mind I can only navigate down the class structure Song.Rating[x].User not
start from User and navigate back to the corresponding Songs without
complex looping through all of the Songs. I may be missing something
fundamental here, but I would have thought that this was a pretty common
problem.

Thanks, Richard



Kevin Spencer said:
Your Song and User classes are just fine. However, your Rating class is
the problem. A Rating doesn't have a song; a song has a rating, or it
may have many ratings. Again, a Rating doesn't have a User, and neither
does a User have a rating. A rating may have a reference to a number of
users, but these are not users; they might only be User IDs from the
database, so that you can fetch information for any user if your
requirements dictate that. The other part of the rating is not a song,
but a score. Does that help?

--
HTH,

Kevin Spencer
Microsoft MVP

Printing Components, Email Components,
FTP Client Classes, Enhanced Data Controls, much more.
DSI PrintManager, Miradyne Component Libraries:
http://www.miradyne.net

I am trying to build a rating engine for a number of users for a list of
songs. I havea database design with a user table and a song table and a
link
table such that each user can rate many songs and each song can be
rated by
many users.

However I am a little stuck on the class design. I hope that this is
the
correct place to post such a question and that someone can help with an
answer.

Simply put each rating has a user and a song, which leads me to three
classes

class Rating
{
Song song;
User user;
}

class Song{}
class User{}


This is the point at which I am slightly confused if I have a rating
object
then I can refer to the song by rating.song and the same for the user.
However If I just want to list all of the ratings for a song, then I
really
need the Song object to be composed of a list of ratings in something
of a
circular relationship.

Whilst this seems to be supported in c#, it does seem to be risky if a
rating has a song, but the song does not include that rating within the
list
of ratings.

Is there another way to build these classes, or is the only way to
describe
the relationship between a rating, a user and a song and between a song
or
user and it's ratings?

I would be grateful for any assistance. I am very confused about this,
so
apologies if my question is confusing.

Richard
 
P

PS

Paul Hadfield said:
I'd say I probably use to fall into this trap too and would have agreed
with you, however a rating is just that. A song might have an average
rating, which is from "many" users. An album may have a rating, which is
from many songs. So having the entity classes containing the
relationships will only cause problems in the future and for maintainance.

Rating as I was defining it represented a single association object between
a user and a song (with a rating score). The overall rating would involve
some averaging or calculation of these objects.

Already the word rating has 3 different meanings. As a score, what was rated
and the overall rating of the song!!!

Ideally the navigational relationships would not involve instansiating new
classes within the entity classes but rather use a custom enumerator
(IEnumerable). The biggest issue may be whether or not the whole object
graph can be loaded into memory.

PS
 
P

PS

RichB said:
Thanks, Your statement that a song has ratings makes sense, though I am
not sure if I just include user ids how I would display (e.g.) the user
name with each rating.

You would look up the user via the key from the list of Users.


Why not have the relationship that Song has many Ratings,
and rating has a User as then if I needed to include anoth user attribute
in my presentation, (e.g.)the user postcode, I would not need to make a
change to my rating class, just use the existing postcode from the user
class?

From this model however I can get Songs, their Ratings and the
corresponding User (note there can only be one user per rating as aswell
as score there is revew text).

But there is no way to get Users and their corresponding Songs. In my mind
I can only navigate down the class structure Song.Rating[x].

There is no direct relationship between a user and a song unless they have
rated it.

User not start
from User and navigate back to the corresponding Songs without complex
looping through all of the Songs. I may be missing something fundamental
here, but I would have thought that this was a pretty common problem.

Thanks, Richard

Some relationships are not necessarily navigatable backwards. The son may
have a parent property but the parent only has a children property, not a
son property.

PS
 
P

PS

RichB said:
Kevin,
Thanks, I think that there is some misunderstanding of the relationship
between songs, ratings and users. If we look at this just as a database of
song information and the ratings that users apply to those songs, which
can be desrcribed by a user making a rating for a song. With many users
making ratings for many songs. Which really translates to user has a list
of ratings and each rating is for one song. Each rating will only ever be
related to one user and one song.

I am fairly happy with the structure that I posted in response to comments
from Paul Hadfield:

Song
{
string artist;
etc
}

User
{
string name;
etc
}

Rating
{
Song song;
User user;
}

SongUserRatings
{
Rating[] ratings;
}

(I note now that I missed including the score in the Rating object)

I am reasonable happy that this will meet my requirements, although I am
slightly concerned by the looping that I shall have to do to identify all
ratings for each song or user.

There is nothing stopping you from having an object/value that represents
some form of summary of the ratings for that song that is pulled from your
database. This would be a read only view.

class Song
{
List<Rating> Ratings;
int OverallRating ...
}

Assuming that there are going to be thousands of ratings per song then
loading each rating, enumerating and calculating may take too long. On the
other hand you may have to provide a detailed view of each rating so you may
need to load some of the Ratings in or all of the Ratings in regardless so
you can decide what works best in order to get the overall rating.

PS
Thanks, Richard


Kevin Spencer said:
Hi Rich,

I only discussed Ratings in my previous message. Yes, a User should have
a collection of Songs, according to your requirement. It is important,
when working with a database back-end, to analyse the architecture of the
database as a database, and your business objects as business objects. A
database has relationships for the purpose of normalization, so that data
doesn't need to be stored redundantly. A set of business classes, on the
other hand, exists to process and manipulate data, and to enforce
business rules. So, you have to think differently when designing one or
the other. The database is just a storage mechanism, while the business
classes represent process that uses the data. In many cases, business
architecture and database architecture are similar, but one does not
dictate the structure of the other.

If we think of Users, Songs, and Ratings as business entities rather than
database (table) entitites , we can define them in terms of what they do.
A Song is a commodity, something used by Users. A Rating or a collection
of Ratings is part of the Song, or belongs to a Song. A User is a
consumer of Songs. So, a User will perhaps have a Collection of Songs,
but the Collection is not redundant. The Songs are commonly used by many
Users, a pool, if you will, or a global Collection. Each User may have
Songs in his/her Collection that are also used by other Users.

Now, the chain of dependency in this case runs in one direction only:
Users have Songs, which have Ratings. While Songs may be shared, Ratings
are not Shared. Each individual Rating is wholly owned by the song it was
created to rate. Furthermore, we need to think about the purpose of
Users, Songs, and Ratings. A User is a multi-purpose entity which
provides an interface for a person to interact with the application,
interact with other Users (perhaps), and interact with other business
entities in the application. A Song is a commodity that is employed by
Users. A User is active, while a Song is passive. A Rating is a commodity
that is employed by Users as well, but it is tied to a single Song. It is
also passive.

The real "trick" here is how the passive Songs can be collected
separately into each User's Songs collection. But if they are in a pool,
and each User has a Collection of references to Songs in the pool, there
is still only one instance of each Song. The Collection is a Collection
of references to Songs, not copies of Songs. Since a class is a reference
type, the pool is actually a Collection of references as well, but its
purpose is to collect all Songs into a single Collection. When a user
adds a Song to his/her Collection, he/she is simply adding another
reference, not adding a Song to anything. Similarly, when the User
removes a Song from his/her Collection, he/she is not deleting the Song,
but removing the reference to the song from the Collection of references.

When a Song instance is created, for example, by a User uploading it, it
is added to the pool. It is the pool that is used to manage the actual
Songs, not the Users who consume them. Again, when it is removed or
deleted, it is deleted from the pool.

A Rating, on the other hand, is a single instance that belongs to a Song,
and is a member of the Song's Ratings Collection. But since the purpose
of the Rating is statistical, and used for the most part in simply
getting the Rating Score for a Song, rather than a handle to a User, it
isn't necessary to add a Collection of User references to the Ratings
Collection, although it could be done.

--
HTH,

Kevin Spencer
Microsoft MVP

Printing Components, Email Components,
FTP Client Classes, Enhanced Data Controls, much more.
DSI PrintManager, Miradyne Component Libraries:
http://www.miradyne.net

RichB said:
Thanks, Your statement that a song has ratings makes sense, though I am
not sure if I just include user ids how I would display (e.g.) the user
name with each rating. Why not have the relationship that Song has many
Ratings, and rating has a User as then if I needed to include anoth user
attribute in my presentation, (e.g.)the user postcode, I would not need
to make a change to my rating class, just use the existing postcode from
the user class?

From this model however I can get Songs, their Ratings and the
corresponding User (note there can only be one user per rating as aswell
as score there is revew text).

But there is no way to get Users and their corresponding Songs. In my
mind I can only navigate down the class structure Song.Rating[x].User
not start from User and navigate back to the corresponding Songs without
complex looping through all of the Songs. I may be missing something
fundamental here, but I would have thought that this was a pretty common
problem.

Thanks, Richard



Your Song and User classes are just fine. However, your Rating class is
the problem. A Rating doesn't have a song; a song has a rating, or it
may have many ratings. Again, a Rating doesn't have a User, and neither
does a User have a rating. A rating may have a reference to a number of
users, but these are not users; they might only be User IDs from the
database, so that you can fetch information for any user if your
requirements dictate that. The other part of the rating is not a song,
but a score. Does that help?

--
HTH,

Kevin Spencer
Microsoft MVP

Printing Components, Email Components,
FTP Client Classes, Enhanced Data Controls, much more.
DSI PrintManager, Miradyne Component Libraries:
http://www.miradyne.net

I am trying to build a rating engine for a number of users for a list
of
songs. I havea database design with a user table and a song table and
a link
table such that each user can rate many songs and each song can be
rated by
many users.

However I am a little stuck on the class design. I hope that this is
the
correct place to post such a question and that someone can help with
an
answer.

Simply put each rating has a user and a song, which leads me to three
classes

class Rating
{
Song song;
User user;
}

class Song{}
class User{}


This is the point at which I am slightly confused if I have a rating
object
then I can refer to the song by rating.song and the same for the user.
However If I just want to list all of the ratings for a song, then I
really
need the Song object to be composed of a list of ratings in something
of a
circular relationship.

Whilst this seems to be supported in c#, it does seem to be risky if a
rating has a song, but the song does not include that rating within
the list
of ratings.

Is there another way to build these classes, or is the only way to
describe
the relationship between a rating, a user and a song and between a
song or
user and it's ratings?

I would be grateful for any assistance. I am very confused about this,
so
apologies if my question is confusing.

Richard
 
P

Paul Hadfield

This is a very good thread, seeing different people's ideas on OO design.
At the "moment" a rating is by a user for a song, but in the future that may
change, if your site then started to handle "videos" your rating class would
have to change

Note: all of this is talking about OO relationships, in the DB, (IMO) you
would have to have a SongRating table, which contained a foreign key
relationship to both the song and the user (and the rating) but that is not
the question here. I think it is an important point (at least to me)
because I feel a lot of my early "OO designs" were in fact objects
reflecting the underlying relational database. It's only when I broke away
from this, my entity classes stopped being big containers / collections to
related entities.

In light of the above, I'd have the following "Entity" objects

User{}
Song{}
Rating{}

I'd then have the following "association" object:

UserSongRating
{
User;
Song;
Rating;
}

I'd then add the following "collection" objects:

UserRatings
{
User; // If user has no ratings, this can just make things easy as you
don't have to go to a separate "user" class instance to get name, etc.
UserSongRatings[];
}

SongUserRatings
{
Song; // same as user above, a song may have no ratings
SongRatings[];
Rating AverageRating(); // function averaging array above
}

Note: the associations don't contain new copies of songs/users/ratings -
rather a reference to the entity instance.

I've found that using the "collection" objects helps with splitting UI and
the business model. They also only need top be populated when required -
this means that when you get a song you don't end up having to read all the
ratings (which in turn could read in all the users, etc). It also helps
with unit tests as the user / song class hasn't had to change at all.

RichB said:
Thanks, I get what you are saying. I thought that you were talking about 2
people's relationship(father to son and son to father), but you are in
fact talking about 3 people (Grandfather, Father and son). You example
structure does however have one anomally, in the PersonRelationships class
you have person, but in relationship you have two people, though surely
you are expressing a relaionship between Relationship.Person and another
person, so only one person is required in the Relationship class.

I need to think about how this applies to my requirements as my
relationships are between different classes not the same class of object
as in this case. If I apply this to my Songs, Users and Ratings, then I
have:

Song
{
string artist;
etc
}

User
{
string name;
etc
}

Rating
{
Song song;
User user;
}

SongUserRatings
{
Rating[] ratings;
}

This way I can simply loop through all SongUserRatings by ratings.song or
ratings.user in order to show corresponding ratings by users for songs or
ratings for songs by users.It still requires looping through the
SogUserRatings, rather than accessing the User from the Song and Song from
the user, but it does make sense to me.

I would appreciate it however if anyone has any further comments on any
other viable approaches.

Thanks, Richard

Paul Hadfield said:
However in practice I only know of how to navigate from the parent to
the child (father.son), not for child to parent.

But a father could be a son and a son a father - otherwise evolution
wouldn't have got very far! You have people, then you have
relationships, similar to my other post, keep them separate and when
required, using a containing class to allow navigation.

Person
{
string name;
}

Relationship
{
RelationshipEnumType;
Person1;
Person2;
}

PersonRelationships
{
Person;
Relationship[];
}




RichB said:
If a rating has a song then the ratings for that song will include that
rating. I don't see what is "risky"? Are you talking about a data
integrity issue?

Yes the risk is that when creating the objects both the List<rating> and
the rating.song need to be populated at the same time to ensure the data
integrity. It would seem that this is extra work that shouldn't be
required. Iif you just model the heirarchical relationship one way, then
on the face of it, you can derive that the father is the son's father
and the son is the father's son. However in practice I only know of how
to navigate from the parent to the child (father.son), not for child to
parent.

Richard


I am trying to build a rating engine for a number of users for a list
of
songs. I havea database design with a user table and a song table and
a link
table such that each user can rate many songs and each song can be
rated by
many users.

However I am a little stuck on the class design. I hope that this is
the
correct place to post such a question and that someone can help with
an
answer.

Simply put each rating has a user and a song, which leads me to three
classes

class Rating
{
Song song;
User user;
}

class Song{}
class User{}


This is the point at which I am slightly confused if I have a rating
object
then I can refer to the song by rating.song and the same for the user.
However If I just want to list all of the ratings for a song, then I
really
need the Song object to be composed of a list of ratings in something
of a
circular relationship.

Relationships can be circular. A man has a father that has children,
one of which is the the man.


Whilst this seems to be supported in c#, it does seem to be risky if a
rating has a song, but the song does not include that rating within
the list
of ratings.

If a rating has a song then the ratings for that song will include that
rating. I don't see what is "risky"? Are you talking about a data
integrity issue?


Is there another way to build these classes, or is the only way to
describe
the relationship between a rating, a user and a song and between a
song or
user and it's ratings?

I would be grateful for any assistance. I am very confused about this,
so
apologies if my question is confusing.

I would start with this:

class Rating
{
Song song;
User user;
int Rate;
}

class Song
{
List<Rating> Ratings
}
class User
{
List<Rating> Ratings
}

PS


Richard
 
K

Kevin Spencer

Hi Rich,

I still believe that you're putting the cart before the horse conceptually,
or in this case, the database before the business objects. The database in
an application supports the business objects, not the other way around. That
is, data that is persisted must be stored somewhere. It is the business
objects themselves which actually represent the process and the data that
they work with. So, rather than thinking of your application as a "database
of song information," you should think of the application as a tool for
users to interact with other users and songs, and to rate the songs. This
point of view enables you to think in terms of functionality rather than
data structure. Yes, you have to think of the structure of your database
when you are designing it, but it is really a servant of the business
classes, a storage mechanism, and its structure has little if anything to do
with the structure of your business classes.

For example, you need to think about *how* the ratings data is going to be
used. It isn't necessary to persist everything in memory, and often this is
a bad idea. As long as the data is available from the database, it can be
fetched when it is needed, with a slight sacrifice in speed. So, when
designing your business classes, you need to think in terms of what they
will primarily be used for, which provides the basic structure for your
classes. For functionality that is less common, data can be fetched "on the
fly" from the database.

Note that I'm not saying your structure is wrong; I'm just trying to give
you a slightly different perspective in terms of how you think of the
components you will be designing. As for the class structure, there are any
number of ways that your classes could be structured. What you want is to
create a structure that is intuitive to the developer (you, and anyone else
that may work on it in the future), and optimizes the use of resources, such
as disk space, memory, and processor, so that it runs efficiently.

--
HTH,

Kevin Spencer
Microsoft MVP

Printing Components, Email Components,
FTP Client Classes, Enhanced Data Controls, much more.
DSI PrintManager, Miradyne Component Libraries:
http://www.miradyne.net

RichB said:
Kevin,
Thanks, I think that there is some misunderstanding of the relationship
between songs, ratings and users. If we look at this just as a database of
song information and the ratings that users apply to those songs, which
can be desrcribed by a user making a rating for a song. With many users
making ratings for many songs. Which really translates to user has a list
of ratings and each rating is for one song. Each rating will only ever be
related to one user and one song.

I am fairly happy with the structure that I posted in response to comments
from Paul Hadfield:

Song
{
string artist;
etc
}

User
{
string name;
etc
}

Rating
{
Song song;
User user;
}

SongUserRatings
{
Rating[] ratings;
}

(I note now that I missed including the score in the Rating object)

I am reasonable happy that this will meet my requirements, although I am
slightly concerned by the looping that I shall have to do to identify all
ratings for each song or user.

Thanks, Richard


Kevin Spencer said:
Hi Rich,

I only discussed Ratings in my previous message. Yes, a User should have
a collection of Songs, according to your requirement. It is important,
when working with a database back-end, to analyse the architecture of the
database as a database, and your business objects as business objects. A
database has relationships for the purpose of normalization, so that data
doesn't need to be stored redundantly. A set of business classes, on the
other hand, exists to process and manipulate data, and to enforce
business rules. So, you have to think differently when designing one or
the other. The database is just a storage mechanism, while the business
classes represent process that uses the data. In many cases, business
architecture and database architecture are similar, but one does not
dictate the structure of the other.

If we think of Users, Songs, and Ratings as business entities rather than
database (table) entitites , we can define them in terms of what they do.
A Song is a commodity, something used by Users. A Rating or a collection
of Ratings is part of the Song, or belongs to a Song. A User is a
consumer of Songs. So, a User will perhaps have a Collection of Songs,
but the Collection is not redundant. The Songs are commonly used by many
Users, a pool, if you will, or a global Collection. Each User may have
Songs in his/her Collection that are also used by other Users.

Now, the chain of dependency in this case runs in one direction only:
Users have Songs, which have Ratings. While Songs may be shared, Ratings
are not Shared. Each individual Rating is wholly owned by the song it was
created to rate. Furthermore, we need to think about the purpose of
Users, Songs, and Ratings. A User is a multi-purpose entity which
provides an interface for a person to interact with the application,
interact with other Users (perhaps), and interact with other business
entities in the application. A Song is a commodity that is employed by
Users. A User is active, while a Song is passive. A Rating is a commodity
that is employed by Users as well, but it is tied to a single Song. It is
also passive.

The real "trick" here is how the passive Songs can be collected
separately into each User's Songs collection. But if they are in a pool,
and each User has a Collection of references to Songs in the pool, there
is still only one instance of each Song. The Collection is a Collection
of references to Songs, not copies of Songs. Since a class is a reference
type, the pool is actually a Collection of references as well, but its
purpose is to collect all Songs into a single Collection. When a user
adds a Song to his/her Collection, he/she is simply adding another
reference, not adding a Song to anything. Similarly, when the User
removes a Song from his/her Collection, he/she is not deleting the Song,
but removing the reference to the song from the Collection of references.

When a Song instance is created, for example, by a User uploading it, it
is added to the pool. It is the pool that is used to manage the actual
Songs, not the Users who consume them. Again, when it is removed or
deleted, it is deleted from the pool.

A Rating, on the other hand, is a single instance that belongs to a Song,
and is a member of the Song's Ratings Collection. But since the purpose
of the Rating is statistical, and used for the most part in simply
getting the Rating Score for a Song, rather than a handle to a User, it
isn't necessary to add a Collection of User references to the Ratings
Collection, although it could be done.

--
HTH,

Kevin Spencer
Microsoft MVP

Printing Components, Email Components,
FTP Client Classes, Enhanced Data Controls, much more.
DSI PrintManager, Miradyne Component Libraries:
http://www.miradyne.net

RichB said:
Thanks, Your statement that a song has ratings makes sense, though I am
not sure if I just include user ids how I would display (e.g.) the user
name with each rating. Why not have the relationship that Song has many
Ratings, and rating has a User as then if I needed to include anoth user
attribute in my presentation, (e.g.)the user postcode, I would not need
to make a change to my rating class, just use the existing postcode from
the user class?

From this model however I can get Songs, their Ratings and the
corresponding User (note there can only be one user per rating as aswell
as score there is revew text).

But there is no way to get Users and their corresponding Songs. In my
mind I can only navigate down the class structure Song.Rating[x].User
not start from User and navigate back to the corresponding Songs without
complex looping through all of the Songs. I may be missing something
fundamental here, but I would have thought that this was a pretty common
problem.

Thanks, Richard



Your Song and User classes are just fine. However, your Rating class is
the problem. A Rating doesn't have a song; a song has a rating, or it
may have many ratings. Again, a Rating doesn't have a User, and neither
does a User have a rating. A rating may have a reference to a number of
users, but these are not users; they might only be User IDs from the
database, so that you can fetch information for any user if your
requirements dictate that. The other part of the rating is not a song,
but a score. Does that help?

--
HTH,

Kevin Spencer
Microsoft MVP

Printing Components, Email Components,
FTP Client Classes, Enhanced Data Controls, much more.
DSI PrintManager, Miradyne Component Libraries:
http://www.miradyne.net

I am trying to build a rating engine for a number of users for a list
of
songs. I havea database design with a user table and a song table and
a link
table such that each user can rate many songs and each song can be
rated by
many users.

However I am a little stuck on the class design. I hope that this is
the
correct place to post such a question and that someone can help with
an
answer.

Simply put each rating has a user and a song, which leads me to three
classes

class Rating
{
Song song;
User user;
}

class Song{}
class User{}


This is the point at which I am slightly confused if I have a rating
object
then I can refer to the song by rating.song and the same for the user.
However If I just want to list all of the ratings for a song, then I
really
need the Song object to be composed of a list of ratings in something
of a
circular relationship.

Whilst this seems to be supported in c#, it does seem to be risky if a
rating has a song, but the song does not include that rating within
the list
of ratings.

Is there another way to build these classes, or is the only way to
describe
the relationship between a rating, a user and a song and between a
song or
user and it's ratings?

I would be grateful for any assistance. I am very confused about this,
so
apologies if my question is confusing.

Richard
 
R

RichB

Thanks for all of your comments, this has given a lot of food for thought. I
think that I need to go back to my requirements and create a model around
the processes required, but I do think that actually rating, user and song
have a fairly loose association and the approaches suggested have
highlighted that to me.

Many Thanks.
Richard
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

Days Gone 0
c# media player problem 1
programming windows media player in c# 1
Windows 10 Itunes/TabKey 0
Let It Be 3
regex question 6
Can I use Excel as a music database? 3
Auto insert into lookup table 1

Top