-1

I'm really confused about this. I just can't find a guide that is designed for noobs or dummies to understand, all i'm getting are advanced or atleast learned technical stuff that i forgot. (not really big into database when i was still learning)

rought outline

So i posted an image of a rough outline i made, i've been at it for hours but my undecisiveness isnt going anywhere, i double guess myself everytime i feel like im on the right track.

In any case, how should i design the tables?

Say for example there's 3 types of account. 1 is for normal, 2 is for trainers and 3 is for gymowners.

I use the accounts table to get the access level of accounts that are logging in. So i'm really confused about this. I'm pretty sure all tables need to have a primary key. so i decided to each have id's on all table.

Like userid, trainerid, gymid.

So how do i FK them onto the account's table? do i add all 3 as an FK? what if it was a normal user then the trainerid(FK) and gymid(FK) would be empty, is that even acceptable for an FK to be null?

The accounts table also have an accountid(PK) not even sure if it is useful at all or since i only need to check the accesslevel col of the accounts table(i'll probably know when i'm deeply involved in it later for now i just cant see the use of a PK on the accounts table except the fact that you need an PK for every table).

So i'm thinking, should i just use the username as the foreign key? but can normal unique cols be foreign key? or do they need to be set to primary keys?

Also, additional question, in regards to the 3 types of accounts, they all basically have a profile, should i make another table that connects to them named profile?(one for each user type ofcourse like user_profile, trainer_profile, gym_profile).

Jay Blanchard
  • 34,243
  • 16
  • 77
  • 119
john
  • 27
  • 5
  • You have a lot of issues floating around in there. The first is basic [database design](http://sqlmag.com/database-performance-tuning/sql-design-why-you-need-database-normalization) and figuring out your entities. Second, you have a security concern. .NET has some nice built in features like [Identity](https://www.asp.net/identity/overview/getting-started/introduction-to-aspnet-identity) that can help. – Steve Greene Jan 10 '17 at 20:38
  • I'm just making a project for myself and not putting them online. If the security issues are about hashed passwords and what not, i was planning on it but i haven't done it yet as i am focusing more on getting a clearer image then implementing them after that i'll take care of the other nuances like security and such. I just want a rough form in which i can polish. – john Jan 10 '17 at 20:58
  • OK, start with your basic entities: Account, Gym, User, Trainer. The primary keys are up to you - I prefer [surrogate keys](http://stackoverflow.com/questions/20052799/surrogate-key-vs-natural-key-for-ef), but you can use natural keys like UserName if you like. Then make relationships between those tables and EF will do the background work. – Steve Greene Jan 10 '17 at 21:06

1 Answers1

0

Maybe one of the problems is that you immediately start to think in tables and IDs and Foreign Keys and so on. It is usually much easier if you think in objects and their relation towards each other.

It is a bit difficult to read your picture. From the text I gather you have the notion of an account, and apparently there are three types of accounts: normal, trainers and gym owners. Is there a difference between those accounts? Do gym owners have properties that normal users don't have? or is it just some kind of identification.

From your drawing it seems that a normal user has a user name, a password and an access level. Do trainers also have these properties?

If so, then in normal object oriented design, you would say it is an aggregation: trainers, normal people and gym owners all HAVE a user name, a password and an access level. aggregation is also quite often called composition. There is a small difference, but for this discussion it is not important.

Instead of aggregation/composition (the object HAs an account) you could also think of inheritance: the object IS an account: trainer accounts, gym owner accounts and normal accounts are objects that are all different kinds of Accounts, with a user name, a password and an access level.

In this example there is not a big difference between aggregation (a trainer has an account), or inheritance (a trainer account is an account). Usually the advise is to favor aggregation over inheritance enter link description here

Be aware: if the only difference between your three accounts is a value of a property, then consider making them all the same type, with a property AccountType which gives you information on whether it is a normal account, a gym owners account or a trainer account.

If the only difference between those three is the access level, then don't create an account type. The access level would serve as account type.

So far, I'm only talking object oriented design. Once you've designed your objects you might think of putting them in a database.

Let's assume a trainer, a gym owner and normal people really are different things, with different properties. Your class would look similar to:

public enum AccessLevel
{
    None,
    ...,
    FullAccess,
}

public class Account
{
    public string UserName {get; set;}
    public string Password {get; set;}
    public AccessLevel AccessLevel {get; set;}
}

public class Trainer
{
   public .. some trainer properties {get; set;}
   // a trainer has an account
   public Account Account {get; set;}
}

public class GymOwner
{
    public ... some gym owner properties {get; set;}
    public Account Account {get; set;}
}

If your design would be like this, you'd see that at least you'd have a gym owner table and a trainer table. But what to do with the Account.

One solution would be to put an account in a separate table and add something to the trainer and the gym owner, so that if you have a trainer you know which item in the account table belongs to this specific trainer.

This method is usually not used in this design. If object A and object B have a one to one relation: one A belongs to one B, and one B belongs to one A, then in fact they can be put into one table. If you use entity framework and you had defined the classes above, the account properties would be added as columns to the trainer table and as columns to the gym owner table. The advantage is that fetching the information about a trainer is faster, as this would involve accessing only one table.

About Primary Keys. Every element in every table should have exactly one primary key. This is the property that identifies the object. If you have the key, you have very fast access to all other properties. To make it easier for you to understand the role of Account I've left out the Id in my original code.

But now that we've decided that it would be best to let Trainers and Gym owners HAVE an account, there would be two tabled: Trainers and GymOwners. Those are the only elements that have a primary key. The classes would be like:

public class Account
{
    public string UserName {get; set;}
    public string Password {get; set;}
    public AccessLevel AccessLevel {get; set;}
}

public class Trainer
{
   public int Id {get; set;}
   public .. some trainer properties {get; set;}
   // a trainer has an account
   public Account Account {get; set;}
}

public class GymOwner
{
    public int Id {get; set;}
    public ... some gym owner properties {get; set;}
    public Account Account {get; set;}
}

Note that there is no table for Account, so Account does not need a key.

So when do you need a foreign key

If a Trainer would not have one account, but several accounts, maybe a lot of accounts, usually called a collection of accounts, then we can't save the accounts as columns inside the Trainer table anymore. We will have to put all accounts of the Trainer in a separate table and tell each account to which trainer it belongs. The account gets a foreign key to the primary key of the trainer to whom he belongs.

In database terms, this is called a one-to-many relation: one trainer has many accounts.

For entity framework the classes would be like:

public class Account
{
    public int Id {Get; set;}
    public int TrainerId {get; set;}

    public string UserName {get; set;}
    public string Password {get; set;}
    public AccessLevel AccessLevel {get; set;}
}

public class Trainer
{
   public int Id {get; set;}
   public .. some trainer properties {get; set;}
   // a trainer has an account
   public virtual ICollection<Account> Accounts {get; set;}
}

public class MyDbContext : DbContext
{
    public DbSet<Trainer> Trainers {get; set;}
    public DbSet<Account> Accounts {get; set;}
}

Note that because Account has its own table it has gotten a primary key. Beside it has also gotten a foreign key in property TrainerId.

I've also added a class derived from DbContext to access the tables. Until know I have only tables with Trainers and tables with Accounts. Each table is called a DbSet, the type of DbSet informs entity framework about the columns in the table.

Because Trainer has a virtual ICollection of Accounts, entity framework knows that there is a one-to-many relation between Trainer and Account, and because of the namer TrainerId, entity framework knows that TrainerId is the foreign key to the primary key of the Trainer that the account belongs to.

So if you have the id of a trainer, you get all accounts of this trainer using the following Linq statements:

int trainerId = GetMyTrainerId();
IEnumerable<Account> accountsOfTrainer = dbContext.Accounts
    .Where(account => account.TrainerId == trainerId);

From the collection of Accounts, take all records where property TrainerId equals trainerId

So now you know how to design a primary key and let a foreign key point to it.

But what about gym owners? If a gym owner only has one account, just let it HAVE the one account (composition). But what if your gym owner also has a collection of accounts.

If you just add the gym owner accounts to the accounts table, then you get in trouble. To which Id does the foreign key point? To primary key in the Trainer table or in the Gym Owners table?

The safest way would be to create GymOwnersAccount and a TrainersAccount. They will each have their own table with a foreign key. A GymOwnersAccount will have a foreign key to the GymOwners table and a TrainersAccount will have a foreign key to the trainers table.

Here you could also decide to let the GymOwners account HAVE an account, but it seems more natural to say the a GymOwners account IS a special type of Account, and thus derives from Account.

public class Account
{
    public string UserName {get; set;}
    public string Password {get; set;}
    public AccessLevel AccessLevel {get; set;}
}

public class GymOwnerAccount : Account
{
    public int Id {get; set;}
    public int GymOwnerId {get; set;}
}
public class TrainerAccount : Account
{
    public int Id {get; set;}
    public int TrainerId {get; set;}
}

public class Trainer
{
   public int Id {get; set;}
   public .. some trainer properties {get; set;}
   // a trainer has an account
   public virtual ICollection<Account> Accounts {get; set;}
}

public class GymOwner
{
    public int Id {get; set;}
    public ... some gym owner properties {get; set;}
    public virtual ICollection<Account> Accounts {get; set;}
}

public class MyDbContext : DbContext
{
    public DbSet<Trainer> Trainers {get; set;}
    public DbSet<Account> GymOwnerAccounts {get; set;}
    public DbSet<Account> TrainerAccounts {get; set;}
}

There are other solutions possible, for instance give each account two foreign keys, one to gym owners and one to trainers, where you always need to set one foreign key to 0. It's easy to see that this might lead to maintenance problems, while it doesn't give you any benefits, so I would advice to stick with separate tables for GymOwnerAccounts and TrainerAccounts.

Now that I've entered the realm of inheritance in database there is a wealth of items you can configure. An article that helped me a lot to understand entity framework, and how classes, inheritance, composition is transferred to databases is Entity Framework Code First

Harald Coppoolse
  • 28,834
  • 7
  • 67
  • 116
  • That was alot somewhere along the lines my brain just got fried, i may need to sleep afterall. I would just like to clarify regarding the 3 account types. I was planning to make a project where you can find gyms online, when you find a gym online, you enroll under those gyms(online or irl payment) after enrolling you can pick programs in which there are trainers to choose from and from one program to the next, the trainer will track your progress and if you are complete the system will recommend further programs. like a skill tree. In any case, each type of user accesses diff functions. – john Jan 10 '17 at 21:45
  • users having profiles is a given, also the gym and trainers. That's why i am confused. I just can't wrap my head around unto designing a rough outline of my database, even without the specifics if i just have a rough outline atleast id have a direction to code. – john Jan 10 '17 at 21:47
  • So you have a class Gym. One gym has many Customers (one-to-many). One gym also has many Trainers, and many gym Programs. Each gym program is performed many times during the week (Gym class?) Each Gym Class has one start time, one stop time and is lead by one (or maybe more) Gym Trainer. Each Gym class is attended by zero or more customers. You see again: think in classes, not in tables. After you know the classes and their relations (HAS / IS, one-to-many or one-to-one), you can have an inkling about the classes and relations you know which tables you need and which primary / foreign keys – Harald Coppoolse Jan 11 '17 at 08:08