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.
Related
I have to create a database structure. I have a question about foreing keys and good practice:
I have a table which must have a field that can be two different string values, either "A" or "B".
It cannot be anything else (therefore, i cannot use a string type field).
What is the best way to design this table:
1) create an int field which is a foreign key to another table with just two records, one for the string "A" and one for the string "B"
2) create an int field then, in my application, create an enumeration such as this
public enum StringAllowedValues
{
A = 1,
B
}
3) ???
In advance, thanks for your time.
Edit: 13 minutes later and I get all this awesome feedback. Thank you all for the ideas and insight.
Many database engines support enumerations as a data type. And there are, indeed, cases where an enumeration is the right design solution.
However...
There are two requirements which may decide that a foreign key to a separate table is better.
The first is: it may be necessary to increase the number of valid options in that column. In most cases, you want to do this without a software deployment; enumerations are "baked in", so in this case, a table into which you can write new data is much more efficient.
The second is: the application needs to reason about the values in this column, in ways that may go beyond "A" or "B". For instance, "A" may be greater/older/more expensive than "B", or there is some other attribute to A that you want to present to the end user, or A is short-hand for something.
In this case, it is much better to explicitly model this as columns in a table, instead of baking this knowledge into your queries.
In 30 years of working with databases, I personally have never found a case where an enumeration was the right decision....
Create a secondary table with the meanings of these integer codes. There's nothing that compels you to JOIN that in, but if you need to that data is there. Within your C# code you can still use an enum to look things up but try to keep that in sync with what's in the database, or vice-versa. One of those should be authoritative.
In practice you'll often find that short strings are easier to work with than rigid enums. In the 1990s when computers were slow and disk space scarce you had to do things like this to get reasonable performance. Now it's not really an issue even on tables with hundreds of millions of rows.
I'm trying to display a list of all Deliveries with the status Dispatched. However, its only returning the number value of the status as opposed to the actual string value. I think this is because I have used Enum to store my status values?
I wish to display the word Dispatched instead of the number value that it represents in the Enum.
I'm developing in ASP.Net MVC and I'm using the query builder in VS2013.
I'm not sure how to approach this, can anyone please suggest an easy to understand solution using SQL.
Let me know if any additional code is required, and thank you in advance!
Here's the Query I want but it doesn't work:
SELECT Delivery.[Status],
COUNT(Delivery.DeliveryID) AS Dispatched_Status
FROM Delivery
WHERE Delivery.[Status] = 'Dispatched'
GROUP BY Delivery.[Status];
Here's the Query that does work but returns a number value. I tried it this way because Enum stores the string value as a number:
SELECT Delivery.[Status],
COUNT(Delivery.DeliveryID) AS Dispatched_Status
FROM Delivery
WHERE Delivery.[Status] = '1'
GROUP BY Delivery.[Status];
P.S I'm aware that status is a reserved word - will be following the correct naming conventions in future.
Delivery Table Definion
It sounds like you just need to add a lookup table in you DB. Something like
CREATE TABLE [dbo].[StatusLookup](
[StatusID] [int] NOT NULL,
[StatusName] [varchar](64) NOT NULL,
[StatusDescription] [varchar](max),
)
INSERT INTO [dbo].[StatusLookup]([StatusID],[StatusName],[StatusDescription]
VALUES(1, 'Dispatched', 'A dispatched record')
...
Note you'll have to manually do this and make sure to populate it with values that match up with your enum.
Then your query would be
SELECT StatusLookup.[StatusName],
COUNT(Delivery.DeliveryID) AS Dispatched_Status
FROM Delivery
JOIN StatusLookup ON Delivery.Status = StatusLookup.StatusID
WHERE StatusLookup.[StatusName] = 'Dispatched'
GROUP BY StatusLookup.[StatusName];
Enums are stored as integers by default.
You can add a separate varchar or nvarchar field to your database table to hold the description of the enum, and populate it using something like the below:
string selectedEnumDescription = Enum.GetName(typeof(DeliveryStatusEnum), Delivery.Status)
The exact implementation depends on how you are saving your records, and what the actual properties and enum names are.
You can then just select the description column in your SQL query.
Either that or you could store the actual enum values and descriptions within a separate table and do a join.
You can store enum in database as a number, usually a small number - the exact type depends on your database. When you read it - you convert a number to enum and work in your code with the enum. When you need to display it, you can call a ToString() method on that enum, for example
public enum Foo
{
A,
B
}
public class Program
{
public static void Main()
{
Console.WriteLine(Foo.A.ToString()); // Prints A
}
}
See it working
You can also use description attribute and print that, see examples here and here
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.
I need to generate an id with the
following features:
Id must be unique
Id consist of two parts 'type' and 'auto incremented' number
'type' is integer and value can be 1, 2 or 3
'auto incremented' number starts with 10001 and incremented each time id
is generated.
type is selected from a web form and auto incremented number
is from the database.
Example: if type is selected 2 and auto incremented number is 10001
then the generated id is = 210001
There may be hundrads of users generating id. Now my question is,
Can this be done without stored procedure so that there is no id confict.
I am using ASP.Net(C#), Oracle, NHibernate
As you use Oracle, you can use a Sequence for that.
Each time you call your_sequence.NEXTVAL, a unique number is returned.
Why isn't the NHibernate implementation of Hi-Lo acceptable?
What’s the Hi/Lo Algorithm
What's the point in having the first digit of the ID to define the type? You should use a separate column for this, and then just use a plain auto-incrementing primary key for the actual ID.
The cleanest way is - as Scott Anderson also said - to use two columns. Each attribute should be atomic, i.e. have only one meaning. With a multi-valued column you'll have to apply functions (substr) to reveal for example the type. Constraints will be harder to define. Nothing beats a simple "check (integer_type in (1,2,3))" or "check (id > 10000)".
As for defining your second attribute - let's call it "id" - the number starting from 10001, you have two good strategies:
1) use one sequence, start with 1, and for display use the expression "10000 + row_number() over (partition by integer_type order by id)", to let the users see the number they want.
2) use three sequences, one for each integer_type, and let them have a start with clause of 10001.
The reason why you should definitely use sequences, is scalability. If you don't use sequences, you'll have to store the current value in some table, and serialize access to that table. And that's not good in a multi user system. With sequences you can set the cache property to reduce almost all contention issues.
Hope this helps.
Regards,
Rob.
If you can't use auto incrementing types such as sequences, have a table containing each type and keeping score of its current value. Be careful to control access to this table and use it to generate new numbers. It is likely it will be a hot spot in your db though.
I have a function that receives three different "people" objects and generates a new "compatibility" object based on the combined values in the "people" objects.
However, about 1/3 of the time the three "people" objects that it receives as input are the same as one before, though possibly in a different order. In these cases I do NOT want to make a new "score" object, but simply return a value contained within the existing object.
Originally, the program just loops through the list<> of "compatibility" objects searching for the one that belongs to these three "people" (since each "compatibility" object contains an array of people objects). This method is really slow considering that there's over thousands of "compatibility" objects and over a million "people" objects.
I had the idea of using a dictionary where the key is a number I generated by combining the three people objects' id values into a single UInt64 using XOR, and storing the score objects in as dictionary values rather than in a list. This cuts down the time by about half, and is acceptable in terms of time performance, but there's way too many collisions, and it returns a wrong score too often.
Any suggestions or pointers would be much appreciated.
Edit: To add to the original question, each "people" object has a bunch of other fields that I could use, but the problem is making a key that is UNIQUE and COMMUTATIVE.
I think you're looking at things in a much too complex manner. Take the 3 PersonID values and sort them,so that they're always in the same order, no matter which order they were passed in. Then set a value in a hashtable using the three PersonIDs as the key, separated with a hyphen or some other character that won't occur in a PersonID value. Then later, check if there's a value in the hashtable with that key.
So if the three PersonIDs are 10, 5 and 22, the hash key could be something like "5-10-22".
Create the key by concatinating objectids after sorting the trio in a pre-determined order.
Your best option would be a custom IEqualityComparer class. Declare your Dictionary like this
Dictionary<List<People>, Compatability> people =
new Dictionary<List<People>, Compatability>(new PersonListComparer());
You'll need to create a PersonListComparer class that implements IEqualityComparer<List<People>>. There are two methods you'll need to implement, one that gets a hash code and one that compares equality. The Dictionary will use GetHashCode to determine if two lists are POSSIBLY equal, and the Equals method to determine if they actually are (in other words, the hash code is fast but could give a false positive but never a false negative). Use your existing hashing algorithm (the XOR) for GetHashCode, then just comare the two lists explicitly in the Equals method.
This should do the trick!
Why not use the names of the people as the dictionary key? (Sort the names first, so that order of passing doesn't matter.)
IE, John, Alice, and Bob become something like my_dictionary["Alice_Bob_John"] <- if that key exists, you've already computed the score, otherwise, you need to compute it. As an alternative to my string hacking above, you could actually use a structure:
NameTriple n = new NameTriple("John", "Alice", "Bob");
// NameTriple internally sorts the names.
my_dictionary[n] ...
If you want to keep everything in memory and not use a database, I'd recommend something akin to a tree structure. Assuming your object IDs are sortable and order doesn't matter, you can accomplish this with nested dictionaries.
Namely, a Dictionary<Key, Dictionary<Key, Dictionary<Key, Compatibility>>> should do the trick. Sort the IDs, and use the lowest value in the outer dictionary, the next value in the next, and the final value to find the compatibility object. This way, there will be no collisions, and lookup should be quite fast.
Or, now that I think again, this doesn't have to be that complicated. Just use a string as a key and concatenate the IDs together in sorted order with a "!" or something else in between that doesn't occur naturally in the IDs.
assuming all "Person" objects are unique, store a UUID in the object.
in your function staticly store the quad (P1,P2,P3,V) where P1,P2,P3 are UUID's of a Person object, sorted (to avoid the ordering problem) and V is the result from the previous calculation.
then your function checks to is if there is an entry for this triplet of Persons, if not it does the work and stores it.
you can store the (P1,P2,P3,V) values in a dictionary, just key off some hash of the three P values