I have to model classes and database tables for a "User" entity.
This "User" entity have this properties:
User
Name
Age
Gender
Email
But I have 2 user's type: "Paid users" and "Free users". Each one have his own properties:
Paid User
Fee
Rate
Free User
Expiration Date
Level
"Paid User" and "Free User" are different, but both are "User".
I'm using ASP.NET MVC, NHibernate and Fluent Maps.
What is the best way and the right design pattern to model this classes and database tables?
Thank you very much!
I often find the best approach for this is to use an inheritance model. All common fields go into the User table. You create an entry in User first, and then use the resulting UserID to create additional entries in Paid User or Free User as necessary.
User
UserID
Name
Age
Gender
Email
Paid User
UserID <-- FK to User
Fee
Rate
Free User
UserID <-- FK to User
Expiration Date
Level
Then you can select (or create a VIEW) like this:
select u.UserID, U.Name, ...
pu.Fee, pu.Rate,
fu.ExpirationDate, fu.Level,
case when pu.UserID is null then 0 else 1 end as IsPaidUser,
case when fu.UserID is null then 0 else 1 end as IsFreeUser
from User u
left outer join PaidUser pu on u.UserID = pu.UserID
left outer join FreeUser fu on u.UserID = fu.UserID
Note: The above schema is pretty naive and doesn't handle cases where a user could be a free user, then a paid user, then a free user again. How you design for this really depends on your application and business rules.
Assuming that in your Object model User would be considered abstract consider the following User table definition:
User
ID
Name
Age
Gender
Email
Type <-- Free/Paid/etc
Paid User
ID
UserID <--- FK to User table
Fee
Rate
Free User
ID
UserID <--- FK to User table
Expiration Date
Level
This will allow you to query in this fashion:
Select * from User where Type = Free
What operations for theese user types?
Any design should start from operations then data structures, not conversely.
Related
I have this table:
User
Name
Role
Mason
Engineer
Jackson
Engineer
Mason
Supervisor
Jackson
Supervisor
Graham
Engineer
Graham
Engineer
There can be exact duplicates (same Name/Role combination). Ignore comments about primary key.
I am writing a query that will give the distinct values from 'Name' column, with the corresponding 'Role'. To select the corresponding 'Role', if there is a 'Supervisor' role for a name, that record is returned. Otherwise, a record with the 'Engineer' role should be returned if it exists.
For the above table, the expected result is:
Name
Role
Mason
Supervisor
Jackson
Supervisor
Graham
Engineer
I tried ordering 'Role' in descending order, so that I can group by Name,Role and pick the first item - it will be a 'Supervisor' role if present, else 'Engineer' role - which matches my expecation.
I also tried doing User.select('DISTINCT ON (name) \*).order(Role: :desc) - I am not seeing this clause in the SQL query that gets executed.
Also, I tried another approach to get all valid Name, Role combinations and then process it offline iterating the result set and using if-else to decide which row to display.
However, I am interested in anything that is efficient and does not over do this handling.
I am new to Ruby and therefore reaching out.
If I wanted to do this in pure SQL, I would have to use GROUP BY.
SELECT Name, MAX(Role) FROM User GROUP BY Name
So one method would be to execute this SQL statement against the base connection.
ActiveRecord::Base.connection.execute("SELECT Name, MAX(Role) FROM User GROUP BY Name")
That would provide exactly the data you need, though it wouldn't be returned as ActiveRecord models. If you need those models then I would use find_by_sql and do an inner join to provide the records.
User.find_by_sql("SELECT User.* FROM User INNER JOIN (SELECT Name AS n, MAX(Role) AS r FROM User GROUP BY Name) U2 WHERE Name = U2.n AND Role = U2.r")
Unfortunately that would provide both records for Graham.
I need help on devise authentication (https://github.com/heartcombo/devise) about logins.
My db design has 3 tables that need 2 joins, so it can use any of a user's emails for login, using a single password.
profiles table
id
name
emails table
profile_id - foreign key from profiles table using has many
email
users table
profile_id - foreign key from profiles table using one-to-one relationship
encrypted_password
At the moment, I can only set 1 join in conditions.
You didn't provide any details except that 2 tables have a FK to a third. So I cannot provide much detail in response. But joining all 3 is a trivial exercise. it'll come in the format of:
select
from profiles p
join emails e on e.profile_id = p.profile_id
join users u on u.profile_id = p.profile_id
where e.email = <email_address_parameter>
and encryption_routine(<password_value_parameter>) = u.encrypted_password;
Assume you have the correct model relations.
if(email = Email.find_by(email: params[:email])).present?
if(email.profile.users.where(encrypted_password: encrypt(params[:password])).count > 0)
# login success
else
# wrong password
end
else
# email not exists
end
I have these tables:
broadcast
id
name
email
id
broadcast_id
user_id
subject
email_open
id
email_id
user_id
I want to keep a count of the email_open records in my broadcast table.
Is the most efficient way of doing this by having a broadcast_id in my email_open table? If it is.. then I know I can just do this in my email_open model:
belongs_to :broadcast, counter_cache: => true
Then, I add a email_open_count to my broadcast table... but I'm wondering if there's a way to do it without doing this.
Also, multiple users can have repeated records in email_open.. how do I make the count be of distinct user_id?
For example, user_id 1 can open an email 5 times but I just want the email_open_count to be 1.
Thanks
So as per your example, if user_id 1 can open an email 5 times but You just want the email_open_count to be 1.You can the same user_id to email or whichever table you want only if that user opens an email but if the user has already open don't save it again.
I have a Rails application with the following models:
User
Bet
User has many_bets and Bets belongs_to User. Every Bet has a Profitloss value, which states how much the User has won/lost on that Bet.
So to calculate how much a specific User has won overall I cycle through his bets in the following way:
User.bets.sum(:profitloss)
I would like to show the User his ranking compared to all the other Users, which could look something like this:
"Your overall ranking: 37th place"
To do so I need to sum up the overall winnings per User, and find out in which position the current user is.
How do I do that and how to do it, so it don't overload the server :)
Thanks!
You can try something similar to
User.join(:bets).
select("users.id, sum(bets.profitloss) as accumulated").
group("users.id").
order("accumulated DESC")
and then search in the resulting list of "users" (not real users, they have only two meaningful attributes, their ID and a accumulated attribute with the sum), for the one corresponding to the current one.
In any case to get a single user's position, you have to calculate all users' accumulated, but at least this is only one query. Even better, you can store in the user model the accumulated value, and query just it for ranking.
If you have a large number of Users and Bets, you won't be able to compute and sort the global profitloss of each user "on demand", so I suggest that you use a rake task that you schedule regularly (once a day, every hour, etc...)
Add a column position in the User model, get the list of all Users, compute their global profitloss, sort the list of Users with their profitloss, and finally update the position attribute of each User with their position in the list.
Best way to do it is to keep a pre calculated total in your database either on user model itself or on a separate model that has 1:1 relation to user. If you don't do this, you will have to calculate sum for all users at all times in order to get their rating, which means full table operation on bets table. This said, this query will give you desired results, if more than 1 person has the same total, it will count both as rating X:
select id, (select count(h.id) from users u inner join
(select user_id, sum(profitloss) as `total` from bets group by user_id) b2
on b2.user_id = u.id, (select id from users) h inner join
(select user_id, sum(profitloss) as `total` from bets group by user_id) b
on b.user_id = h.id where u.id = 1 and (b.total > b2.total))
as `rating` from users where id = 1;
You will need to plug user.id into query in where id = X
if you add a column to user table to keep track of their total, query is a little simpler, in this example column name is total_profit_loss:
select id, total_profit_loss, (select count(h.username)+1 from users u,
(select username, score from users) h
where id = 1 and (h.total_profit_loss > u.total_profit_loss))
as `rating` from users where id = 1;
Am having a table with quetion_id , nominees and vote_count. In which the values for question_id and nominees are prepopulated from other tables with vote_count as zero.
If the users select some nominees the vote count should be incresed by one. The problem is How to connect the question_id and nominees like for this question_id this nominee is selected .
can some one give example for this situation..
I'll answer based on this scenario:
So you have a...
1) User
who can...
2) Vote
for a...
3) Nominee
And it's a given that MANY users can vote for MANY nominees.
You probably aready have tblUser and tblNominee - so you need a link table that can contain the votes (tblUserNomineeVote).
tblUserNomineeVote has fields for UserId and NomineeId, and therefore registers a vote. You may need to add constraints depending on how many votes a user can register etc.
You can then use:
SELECT
tblNominee.Name,
COUNT(*)
FROM
tblNominee
INNER JOIN
tblUserNomineeVote ON tblUserNomnieeVote.NomineeId = tblNominee.NomineeId
GROUP BY
tblNominee.Name