I am new to mvc4 and trying to develop a new application where I have three user in table Employee, admin and customer. The problem is that customer has many fields than employee or admin so I cannot make a single user table and then I made a different table for each user where username and password is included. Now I am lost when I want to authenticate user from their respective table. Is it possible or should I make user table separately with username and password? But doing so should I have to first create user every time before I create customer, employee and admin?
so i cannot make a single user table
Sure you can. Just separate the "users" from the "details about the users." For example, say you have a Users table here:
Users
---------
ID (PK)
Username
Password
(maybe a few other fields)
Then you san sub-type some other tables off of this one. Tables like:
Employee
----------
ID (PK, FK to Users)
Name
EmployeeNumber
etc.
Customer
----------
ID (PK, FK to Users)
Name
CustomerNumber
etc.
Admin
----------
ID (PK, FK to Users)
(you get the idea)
Very similar to sub-classing in an object-oriented system, this allows you to sub-table in a relational system. The login components in the application are only concerned with the Users table, then once authenticated the other components can get information about the user from the other tables. (This has the added benefit of allowing a single user to be more than one thing. Such as an Employee who is also an Admin.)
Edit: Keep in mind this is based on knowing very little about your relational data needs. You might also be able to accomplish the same thing using a setup like:
Users
----------
ID (PK)
Username
etc.
Roles
----------
ID (PK)
RoleName
UsersInRoles
----------
UserID (FK to Users)
RoleID (FK to Roles)
(Other tables about users)
This setup is a lot closer to what's built in to the ASP.NET membership system as well, so you may be able to benefit significantly from it. Though based on your description of your user data you may still need to sub-type some tables containing the user information in order to avoid having lots of null values.
Related
Currently I am designing a Customer Management System, which include Customer's Company Information and their Contacts.
My design is in below photo.
https://i.stack.imgur.com/FecUU.png
In this photo, you can see Label and TextBox of Customer ID, Company Name, Address Line, Company Tel, Fax, Pay Terms and a Group of Contact, Tel, Email.
In my past design, I created a Table to store all the data, and named the group as multiple columns contact_1, tel_1, email_1, contact_2, ... email_8. This design allow me to easy query the data but bad in data binding. So I think I should make a new design for this.
My new design is to separate the Group of Contact, Tel, Email to another Table. So that the list will remain the Customer ID, Company Name, Address Line, Company Tel, Fax and Pay Terms. The list (without AddressLine1 ... AddressLine4) are showed in this Page design).
https://i.stack.imgur.com/7OINI.png
The left column is the id column which I used for edit action (use SELECT columns FROM customer_list WHERE id='id' in the Edit Window, id is obtained by (this.CustomerDataGrid.SelectedItem as DataRowView)["id"]). I have set Visibility.Collapsed to hide the id column in C# code for better view.
However, since I should not make a Table inside a Table, the data of Contact, Tel, Email (Customer Contact List) will be INSERT in another Table as contact, tel, email column. Then I have to find way to link the Customer Contact List's Table to the Customer List.
As no data is created at this stage, I think if I can find the last_value of the id column sequence of the Customer List's data, then I can create a Customer Contact List's Table which is related to the Customer List's data.
The solution I found is to use SELECT last_value FROM customer_list_id_seq to get the last_value. After the query, I make a variable current_value = last_value + 1 to get the next sequence value. With this value, I can create a table customer_contact_list_#current_value which is "related" to the non-created Customer List's data.
I know that I could save the non-Customer Contact List data first and get the last id value of customer_list by SELECT id FROM customer_list ORDER BY id DESC LIMIT 1. My concern is that: If I have to add more Contact, I still able to make a new design, convert the Group of Contact, Tel, Email to a DataGrid in WPF.
As I am new to programming, my mindset and design knowledge are only in basic stage.
In this design, the data are separated in two Table which means that they have no relationship.
I have to make the Customer Contact List's Table name related to customer_list.id to make them like having a relationship. Also, in this design, I have to created a new Customer Contact List's Table for each Customer List's Data (row).
I would like to know if there are better approach of this design.
My another design is to add three columns to the customer_list table., but then my Query will be complex as I have to make duplicate "Customer ID, Company Name, Address Line, Company Tel, Fax, Pay Terms" and try to filter them. Even if I set the other 7's row duplicate value to null, the table will look hard to read.
Well you are on your with the last comment creating a Foreign Key. So we have a relationship between Customers and Contacts. However the outstanding question becomes what type is Customer:Contact relationship?
One-to-One (1:1) -> Each Customer has one contact and a Contact is for one customer.
One-to-Many (1:M) -> Each Customer has many contacts and a Contact is for one customer.
Many-to-Many (M:M) -> Each customer has Many Contacts and Each Contact is for many customers.
From your description discard 1:1. For 1:M the you include the customer PK in the contact table. For the M:M you actually create another table that contains the PK from both Customer and Contact.
As for generating ids do not even try to get the last one and increment it (generally referred to as MAX+1). In a multiple user environment it is a virtual guarantee you will get a duplicate. Simply create a sequence or a generated identity for each table and Postgres will handle it.
Tables for 1:M, Postgres v10 and above
create table customers( cust_id integer generated always as identity
, address text
, tel text
, fax text
, pay_terms text
, constraint cust_pk primary key (cust_id)
)
create table contacts( cont_id integer generated always as identity
, cust_id interger
, tel text
, email text
, constraint cont_pk primary key (cont_id)
, constraint cont_2_cust_fk
foreign key (cust_id)
references customers(cust_id)
);
Table definitions for M:M, Postgres v10 and above
create table customers( cust_id integer generated always as identity
, address text
, tel text
, fax text
, pay_terms text
, constraint cust_pk primary key (cust_id)
)
create table contacts( cont_id integer generated always as identity
, cust_id interger
, tel text
, email text
, constraint cont_pk primary key (cont_id)
);
create table customer_contacts( cust_id integer
, cont_id integer
, constraint cust_cont_pk
primary key (cust_id, cont_id)
, constraint cust_cont_2_cust_fk
foreign key (cust_id)
references customers(cust_id)
, constraint cust_cont_2_cont_fk
foreign key (cont_id)
references contacts(cont_id)
);
For Postgres versions prior to v10, replace integer generated always as identity by serial.
I have two tables
contact table
contactID (PK auto increment)
FirstName
LastName
Address
etc..
Patient table
PatientID
contactID (FK)
How can I add the contact info for Patient first, then link that contactID to Patient table
when the contactID is autoincrement (therefore not known until after the row is created)
I also have other tables
-Doctor, nurse etc
that also links to contact table..
Teacher table
TeacherID
contactID (FK)
So therefore all the contact details are located in one table.
Is this a good database design?
or is it better to put contact info for each entity in it's own table..
So like this..
Patient table
PatientID (PK auto increment)
FirstName
LastName
Address
Doctor table
DoctorID (PK auto increment)
FirstName
LastName
Address
In terms of programming, it is easier to just have one insert statement.
eg.
INSERT INTO Patient VALUES(Id, #Firstname,#lastname, #Address)
But I do like the contact table separated (since it normalize the data) but then it has issue with not knowing what the contactID is until after it is inserted, and also probably needing to do two insert statements (which I am not sure how to do)
=======
Reply to EDIT 4
With the login table, would you still have a userid(int PK) column?
E.g
Login table
UserId (int PK), Username, Password..
Username should be unique
You must first create the Contact and then once you know its primary key then create the Patient and reference the contact with the PK you now know. Or if the FK in the Patient table is nullable you can create the Patient first with NULL as the ContactId, create the contact and then update the Patient but I wouldn't do it like this.
The idea of foreign key constraints is that the row being referenced MUST exist therefore the row being referenced must exist BEFORE the row referencing it.
If you really need to be able to have the same Contact for multiple Patients then I think it's good db design. If the relationship is actually one-to-one, then you don't need to separate them into two tables. Given your examples, it might be that what you need is a Person table where you can put all the common properties of Doctors, Teachers and Patients.
EDIT:
I think it's inheritance what you are really after. There are few styles of implementing inheritance in relational db but here's one example.
Person database design
PersonId in Nurse and Doctor are foreign keys referencing Person table but they are also the primary keys of those tables.
To insert a Nurse-row, you could do like this (SQL Server):
INSERT INTO Person(FirstName) VALUES('Test nurse')
GO
INSERT INTO Nurse(PersonId, IsRegistered) VALUES(SCOPE_IDENTITY(), 1)
GO
EDIT2:
Google reveals that SCOPE_IDENTITY() equivalent in mysql is LAST_INSERT_ID() [mysql doc]
EDIT3:
I wouldn't separate doctors and nurses into their own tables so that columns are duplicated. Doing a select without inner joins would probably be more efficient but performance shouldn't be the only criteria especially if the performance difference isn't that notable. There will many occasions when you just need the common person data so you don't always have to do the joins anyway. Having each person in the same table gives the possibility to look for a person in a single table. Having common properties in a single table also allows you have to have doctor who is also a patient without duplicating any data. Later, if you want to have more common attributes, you'd need to add them to each "derived" table too and I will assure you that one day you or someone else forgets to add the properties in one of the tables.
If for some reason you are still worried about performance and are willing to sacrifice normalization to gain performance, another possibility is to have all person columns in the same table and maybe have a type column there to distinguish them and just have a lot of null columns, so that all the nurse columns are null for doctors and so on. You can read about inheritance implementation strategies to get an idea of even though you aren't using Entity Framework.
EDIT4:
Even if you don't have any nurse-specific columns at the moment, I would still create a table for them if it's even slightly possible that there will be in the future. Doing an inner join is a pretty good way to find the nurses or you could do it in the WHERE-clause (there a probably a billion ways to do this). You could have type column in the Person table but that would prevent the same person being a doctor and a patient at the same time. Also in my opinion separate tables is more "strict" and more clear for (future) developers.
I would probably make PersonId nullable in the User table since you might have users that are not actual people in the organization. For example administrators or similar service users. Think about in terms of real world entities (forget about foreign keys and nullables), is every user absolutely part of the organization? But all this is up to you and the requirements of the software. Database design should begin with an entity relationship design where you figure out the real world relationships without considering how they will be mapped to a relational database. This helps you to figure out what the actual requirements are.
I want to implement an audit table and I have no idea how am I supposed to get the username.
I am using C# and Sql Server. I have a Users table in my database. When I log in my windows form application I verify if the correct combination of username and password is used. But how do I inform the database of the current user? I thought of adding an extra column to my Users table in which to set on 1 the logged username. Is that a solution for single-user? But my application in supposed to support multi-user. What could be done in this case?
Depending on your authentication scheme, you need to get the the User name.
for thick client applications,
Environment.Username
and
System.Security.Principal.WindowsIdentity.GetCurrent()
are a couple of options.
typically for audit tables, there is a column called 'ModifiedByUser' where you can log the user name provided by the win form app.
create the nvarchar and datetime columns (if not already) in your audit table.
one will stored the user name and the other the datetime of the audit action.
in your code, whenever you want to add an entry to the audit table, get Environment.Username or System.Security.Principal.WindowsIdentity.GetCurrent(), along with DateTime.UtcNow and pass it on to be saved to the DB into the Audit table.
SQL Server knows who you are. You can simply use SUSER_SNAME() or/and ORIGINAL_LOGIN() function as a default value for the username column in your audit table. Same for the time of audit event, use GetDate() function. There is no need to send this information from the client.
This is a very open-ended question but I think I understand what you are trying to do. You have application-specfic users that are defined in a Users table (as opposed to using database users or active directory users) and you need to log specific information for auditing purposes or drive security based off of the logins. Is that correct?
This can be done, but the logic for it will need to be written in your application.
Let’s pretend we are writing a program to send out an invoice to a customer.
I used role based security where you can give users access to do specific tasks by granting them a role. For example, “Create New Invoice” could be a role. I usually have 2 tables for this:
SecuirtyRoleDefintion
SecurityRoleUsers
The fist table, Security Role Definition will have an ID column, the Description (“Create New Invoice”), and I usually have a Audit column to indicate if this action needs to be logged for Audit.
The second table, SecurityRoleUsers, is where I define if a user has permission to execute that role. Columns are usually something like this: a unique ID, User ID (foreign key to the Users table), RoleID (foreign key to SecurityRoleDefintion)
Now in your application we need a class to check if a user has a role. It needs to take in the role ID (or name) and the user ID. Example: public bool IsUserAuthorized(int RoleID, int UserID)
This method can run a query on your SecurityRoleUsers table to see if the user is in the table for that role. If so, it returns true. If not, it returns false.
Now back in the application when user click the “Create New Invoice” button it runs the IsUserAuthorized() method to check if a user can perform the operation.
If creating an audit log is necessary, you could do something similar. After the security check is done for “Create New Invoice” you can check to see if the Role needs to be audit logged, if so then write to an Audit table.
DECLARE #username varchar(128)
SET #username = CONVERT(VarChar(128), CONTEXT_INFO());
PRINT #username
DECLARE #ID_User int
SET #ID_User = ( SELECT Users.ID_User
FROM Users
WHERE Users.Username=#username )
PRINT #ID_User
This is how I solved it. I inserted this piece of code in each update trigger.
How would you design a database to manage multi organisation?
(ie 1 user can own/manage more than 1 organisation)
Example
Xero (www.xero.com), you can login to xero then select the company on the list that you want to manage. I think freshbook has something simular.
USER_ACCESS
Id
CompanyUserId (UserId of company)
UserId (UserId that will manages company)
USER_PERMISSION
Id
UserAccessId
CanViewM
CanEditM
....
CanViewN
CanEditN
You should not mix users and logins. They should be kept treated as seperate tables/objects. As ones role in one company might not be the same role as in the other company.
Also do not create a permission table with one column for each possible permission. Instead you should create one row per allowed permission. (and if needed one table defining all permissions)
Hence you should have tables like:
USER_ACCOUNT (used to define logins)
Id
UserName
Password
USER
Id
AccountId (account used for login)
CompanyId (company that the user belongs to)
PERMISSIONS
Id
Name
USER_ALLOWED_PERMISSIONS
UserId
PermissionId
When logging in, simply check the USER table if more than one row is returned for the account and display a select user form if needed.
I am new to SQL and been given a task. Following are the details:
What I have:
A C# desktop application for User login and view user status (only two options: user logs in and check status of all users that are dummy created)
A table named USER containing
id
username
datecreated
A table named LOGINSTAT containing
id
username
Logtime
logDate
What I have to implement
I have to save time and date when ever user logs in in LOGINSTAT table using SQL.
My question
My question is how can I implement that. I can do the coding part but I am interested in getting some good advice to implement it. I think of it as a formal way as I know to do it:
when user logs in insert values into the login table giving all the required values.
BUT
I think that might be a bit odd. Some of my friends said you may be able to implement it by use of foreign key and primary keys, but the problem lies that the user may log in many time in a day. How to keep track of login time and date in that case?
You don't need username in your LOGINSTAT table.
You'll probably want the LOGINSTAT to include:
id
u_id
loginDateTime
id is the unique ID of every login
u_id is a foreign key from the id in users that matches your log event to a user
loginDateTime is a datetime that will give you both your log date and log time in one column
What is unique in LOGINSTAT? Not user by itself, but ID+LogDate+LogTime should be. That would be your primary key.
The only foreign key is in LOGINSTAT: ID, which references the ID in the USER table.
Values in a PRIMARY KEY column (eg. USER.id) must be unique from one another.
Values in a FOREIGN KEY column in another table referencing that primary key (eg. LOGINSTAT.id referencing USER.id) do not need to be unique - you can have multiple records in a table have the same foreign key column reference the same primary key.