I have an Enum called RoleEnum with four values User (1), Supervisor (2), Admin (3), and ITOperator (4). I have an Announcement table that obviously stores Announcement data (title, text, start and end date). However, I'd like to be able to add a new column called Roles that defines which users in which roles can see the announcement.
Normally when storing Enums in SQL I just use the smallint data type, however that isn't going to work in this situation because an announcement can be seen by more than one role.
What I was considering doing was having the Roles column defined as a varchar(x) and comma delimiting them when they were stored. However, I don't think/know if that is the best route to take. I don't want to create a new table to hold a one-to-many relationship.
Any ideas?
If you care about maintainability, I'd stick with third normal form as much as possible.
Roles
RoleID RoleName
1 User
2 Supervisor
3 Admin
4 ITOperator
Announcements
AnnouncementID Title ...
1 Foo ...
2 Bar ...
AnnouncementsVisibility
AnnouncementID RoleID
1 1
1 2
2 2
2 3
2 4
This is one possible solution - not guaranteed to be the best but it doesn't require a new table.
You can add the [Flags] attribute on your enum - this makes the enum a bit field where individual enum values can be masked together. Your enum would then look like this:
[Flags]
public enum RoleEnum : long
{
User = 1,
Supervisor = 2,
Admin = 4,
ITOperator = 8
}
You can use the '|' (bitwise OR) operator to mask multiple roles together in a single 64-bit integer, which you can store in the database in an integer field (a bigint).
RoleEnum userRoles = RoleEnum.User | RoleEnum.Admin;
If you don't need 64 possible roles, you can drop down to using an int instead - that gives you 32 possible distinct roles.
Just do as Entity Framework would do and store them as ints.
Check this out to learn more... MSDN
Related
My current schema looks like the following:
ID | DisplayVal
-- ----------
1 1-H-3
2 2-H-3
3 3-J-4
In the above, the ID field is an IDENTITY INT field which is also used as and end user account Id. The DisplayVal is what they see on the screen.
A new client has provided their own Account Id values, but they are alpha-numeric, so they can't just go into the IDENTITY field. Here are my scenarios: I am looking for a scenario that would offer the best maintainability, end user experience, magnitude and impact of changes and testing/QA impact.
My first scenario was to add an Account Number column that would be a VARCHAR(x) and accommodate all types of Account Numbers. It would look like this:
ID | DisplayVal | AccountNumber
-- ---------- -------------
1 1-H-3 1
2 2-H-3 2
3 3-J-4 3
4 h389 h389
5 h-400-x h400
In the above, in the case of the first client, the seeded Identity which is the Account Id would be copied into the Account Number, but for the other client, there would still be a seeded Identity created, but their Account Number would be different and it may or may not match the Display Value.
My second scenario was to not add any columns and for clients that provide an Account Number, I would turn off IDENTITY INSERT and insert the new Id's and then turn identity insert back on. If a client did not provide an Account Number, I would auto-generate one, obviously trying to avoid collisions.
The third scenario was basically to leave the new Account Number as a legacy Account Number and create new identity values for all new records. This would require the end-user to become familiar with a new Account Number. It is probably the easiest, but not sure if there are any downsides.
If there is another scenario you know that would work well in this case, let me know.
You should not use business keys, like account id, as identity. Create a new id column and populate it either using an autoincrement field or a guid. Your users or other systems that interact with your system should not know/depend on this value.
My question is :
I have a domain table in database, where I add some rules for users.
Something like this:
Table UserRoles:
idRule cRuleDescription bRuleIsActive
1 Edit client true
2 Delete client false
My C# application refers to this table using enumeration, like this :
public enum UserRoles: int
{
CanEditClient = 1,
CanDeleteClient = 2,
CanChangeClientName = 3,
//More code
}
And I use a C# method that query the database, by its Id, to know if the logged user has permission for some action. Something like this:
bool HasPermissionToEdit = Rules.UserHasPermisson(UserName, UserRoles.CanEditClient)
if(HasPermissionToEdit)
{
//Do the work!
}
But using this gives me some trouble. Someone created new rows in a production eviroment on database. And the ids are not correct anymore. And I'll need to change the enumeration on my C# code. I need to use this table because, administration users can manage the rules for other group of users.
How do you work with it? There is a better way to reference a registry on a table?
If you want to implement this properly, make the key contain the name of the role. That way, there cannot be accidents with the ID's where someone thinks the key is meaningless. Naming it idRule does not help.
Second, add a check constraint to enforce correct usage of role names.
Third, add a unique key constraint on the name of the role to enforce that each role only occurs once.
You can use string enums to convert from the role names to integers if you want to. See C# String enums for a nice design pattern.
Example table:
ID - NAME - DESCRIPTION - IS_ACTIVE
1 - CanEditClient - client - true
2 - CanDeleteClient - client - false
3 - CanChangeClientName - client - true
Then make sure to add a unique constraint to NAME and a check constraint as well.
Now, no matter how someone shuffles the ID's, your code will continue to work.
Using the rule ID to map to an enum is not crazy in itself as long as the rule ID is not automatically generated (i.e. not an identiy column).
If i have a field in my db which clarify the type of the application .
takes two values 0 or 1
0 for web app and 1 for win app
and now there is some requirement in my business:
There are some win applications available to all users and some of
them belong to specific users .
What 's the best solution to handle this case .
adding new field to state whether it's public or private
or just adding new value to the same field say 2 to state it's private win app
If you haven't already it would probably be best to slip in a user, role, permission based security model to the database/system, thereby giving you the ability to specify a group of users that have access to a particular application, whether it be web or windows based
I'd say add a new column next to your AppId called PublicIndicatior
Oh and be sure to have a lookup table so people can see what 0 or 1 means, and foreign key it to your data table
Lookup Table:
AppTypeId, AppTypeDescription
0, WebApp
1, WinApp
Data Table:
Id, AppTypeId, PublicIndicator
1,0,1
etc
As Pope suggested above (I +1 him), the best scenario is to add in a new user table (or tables for roles etc if possible) and then link to that through either a new foreign key, or using the appid (assuming it is on your table and unique). Then when the boss comes back 3 weeks later and say, "that's great, but now can we restrict App99 to just the Accounts Dept" you are not going back to the drawing board.
I read this statement in a C# book.
Enumerations do not necessarily need
to follow a sequential ordering, and
need not have unique values.
If I understand that statement, it means one of this is acceptable (I don't know which):
1.
enum EmpType
{
Manager = 1,
Grunt = 1,
Contractor = 100,
VicePresident = 9
}
2.
enum EmpType
{
Manager = 10,
Manager = 1,
Contractor = 100,
VicePresident = 9
}
Can someone please explain to me? I thought C# was supposed to be a subset of C/C++.
The first one would be valid, you may have duplicate Values not duplicate Names
1 is correct, 2 is not.
As the book says, enums need not have unique values (example 2 shows enums with non-unique names). Names must be unique, as it is how the compiler matches it up to a value.
Actually - why not to check :) Each enum is subclass of System.Enum class (specially handled), each enum element is a static field initialized with a literal value - you cannot have two fields with the same names, but can have fields with the same values, so #1 will work, #2 won't.
Number 1 is acceptable. Number 2 throws a compile time exception. You can have multiple Equivalent values. But not equivalent duplicate names.
For example, suppose you want to define an enum for a companie's personnel job levels. You have staff, management. staff include sales department and IT department and it doesn't make any difference for you if a person is in sales or IT, He/she is considered staff anyway. You can define the following enum:
public enum PersonnelLevels
{
Management=0,
Sales=1,
IT=1
}
Refering to enum (C# Reference):
The default underlying type of
enumeration elements is int.
You can assign any integer value to any enumuration element. You can assign duplicated values to different elements. However, elements names must be unique.
That means, block one is correct. But, block two is not.
At the moment I have a SQL Server 2005 table that looks a bit like:
ID | name | desc
----------------------
1 | ONE | Value One
3 | THREE | Value Three
5 | FIVE | Value Five
This table corresponds with an enum in C# that looks like:
enum MsgTypes{
<summary>Value One</summary>
ONE = 1,
<summary>Value Three</summary>
THREE = 3,
<summary>Value Five</summary>
FIVE = 5
}
So my question is this: Is there a good way to associate the enum to the SQL table so that any changes/additions to the values in the table don't need to be manually made in the c# code?
If you want it to be somewhat dynamic, why make it an enum to start with? Just fetch the details from the table on app startup, and remember them in (say) a Dictionary<int, string>. You could always encapsulate the value within your own value type which enforced the range, if you wanted to.
Alternatively, if you don't mind recompiling, you could fetch it at build time and autogenerate the enum source code.
I had to have a think about something similar recently (refactoring an enum) -- basically I considered using a Dictionary<A, B> to store the enum values in. You could dynamically load from the table to populate the dictionary if you wanted to.
One thing I'd add -- is if you're replacing an enum that already exists with something dynamic you'll have to think about what you're going to do with exceptions raised as part of populating it dynamically.
To me it depends on how often the enums/DB lookup tables change. We have about a half dozen enum/lookups like this in our system, and i don't mind recompiling to add an emum option + DB row becuase:
It doesn't happen very often - probably twice in the past year that i can think of
There is usually new business logic surrounding the new option so coding is necessary anyway.
Another alternative would to implement a custom object with ID, Name, and Desc properties that would encapsulate the database table.
I accept with what Jon is suggesting, but then if you prefer to have your Enum list in the DB and want to use them in your code, you could use TypeTable feature from nHydrate for your project.