Hi I came to this situation working in my project, where people hardcode the value of a primarykey column in an application. Is it a good practice. while dealing with environments the value of that record might change but how about using identity inserts to other environments.
While this is obviously a very poor practice, I hesitate to reject anything like this without decent information on the reasoning. I usually give my colleagues the benefit of the doubt and assume they have thought about the problem and come to a reasonable conclusion, and I simply need to learn to understand their reasoning.
There are certain very rare cases where hardcoded identities can be an OK solution, for example if your installation package also creates the database and the schema and seeds certain domain lookup values so they are the same on every system. In cases like these, the identity column is defined with a seed that is a little higher than usual (e.g. IDENTITY(100,1)) and the system values are always placed below the seed (in this case, 100).
For example, maybe you have a domain table for PhoneType and values 1-3 are reserved for "Primary," "Billing," and "Contact." Meanwhile values 100 and up are allowed for end users to define their own phone types.
It is definitely a poor practice to insert hardcoded identity values during run-time proper, e.g. in response to user input. In that case it is probably better to find a natural key, use a GUID, or develop your own identity tracking system.
Typically I've seen this where there are constants in the code base (like enums for some kind of basic system types which are fundamental to the application) that are also in the database (as lookup tables). There are some better ways to handle this, but ultimately, something is always going to get hardcoded in these cases, even if it isn't the primary key. A primary key might be a natural key, for instance.
Typically you would only see this being acceptable for very fundamental entities. Perhaps a type of organization or entity in a program like: TYPE_USER, TYPE_GROUP. You would not see this for lookups which are typically user-modifiable, or expecting to be extensible, or not fundamental in some way, like VEHICLE_TYPE_CAR, VEHICLE_TYPE_SUV, VEHICLE_TYPE_RV, VEHICLE_TYPE_MOTORCYCLE, etc.
In any case, it is a code smell, and it's not a practice that's a good idea unless it's a fundamental immutable enumeration in the architecture.
I agree with all the replies here thus far and I also face certain situations where I need to check a condition on a certain value that is based on the primary key. As Siyual has stated, checking for this condition against a more explanatory field makes more sense.
One way of dealing with this could be to add another column in the entity describing the row, and use that as a conditional check that gets mapped to an enum.
e.g. Table:
+-----+----------+-------------+
| PK | Status | Enum_mapped |
+-----+----------+-------------+
| 101 | Fitted | 1 |
| 201 | Unfitted | 2 |
| 301 | Used | 3 |
+-----+----------+-------------+
Code:
private enum Statuses
{
Fitted,
Unfitted,
Used
}
private int GetStatus(int enumstatus)
{
return enumstatus = ctx.myStatus.Where(a => a.Enum_mapped == enumstatus).Select(a => a.PK).FirstOrDefault();
}
Call the appropriate status:
GetStatus((int)Statuses.Fitted);
Result = 101
Related
I think I got an architecture problem.
For the example purpose let's say I have a table named Dict.Country with two columns : Id and Name like below. The reason why I have such a table and not only Enum in code is because with time we want to dynamically add another values.
1 USA
2 POLAND
3 CHINA
etc.
So now is the question, how to correctly read and operate on these values? I can create class DictElement with string fields Id and Column, then read them from database and operate, but we got the problem that we have to operate on strings literals:
if (x.country == "POLAND")
...
which I believe is bad practice, cause one small misspelling can make us much troubles.
Is there any good practice how to work on such dictionaries from database?
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 am migrating an old database (oracle) and there are few tables like CountryCode, DeptCode and RoleCodes, their primary key is string (Codes) and i am thinking about adding Number column as a primary key because it would work fast with joins. These tables are not really big.
I am wondering if primary key for those tables should start from number '1' or it can be started from 100 just to differentiate b/w tables PK although i don't think i would be showing them on reports.
For sequence-generated IDs, I would suggest starting at different values if it's easy to do (depends on your database etc). You shouldn't be using this to differentiate between them in code, but it can make testing more reasonable.
Before now, I've had a situation where I've accidentally used a foreign key one table as if it were the foreign key for another table. The tests passed as the IDs were coincidentally the same. After we discovered the problem, we changed the initial seed and found the tests were a lot clearer.
You shouldn't do it to differentiate between tables. That is just not practical.
Not all primary keys have to start at 1, as in the case of an order number.
The rationale you're using to switch to an integer primary key doesn't seem valid: the performance gain you'd see using an INT rather than the original codes (which I assume are strings) will be negligable. The PK is always indexed, and indexes for strings or numerics are as good as instant. So unless you really need an INT, I'd be tempted to stick with the original data-type and work with the original data - simplifies data migration (which is something that should be considered whilst doing any work).
It is very common for example in ERP systems to define number ranges that
represent a certain group of items.
This can be both as position in a bigger number, e.g.
1234567890
| |
index 4 - 6 represents region code
index 7 - 8 represents dept code...
or, as I suspect in your case, parts at the same place, like
1000 - 1999 Region codes
2000 - 2999 DeptCode
3000 - 3999 RoleCode
Therefore: No, it not necessarily starts with 1.
Bigger ERP Systems have even configuration sections for number ranges!
Now, from a database point of view:
Yes, your tables should always have a primary key!
Having one will tremendously improve performance on average cases.
(but in most database systems, if you do not provide one, one will be
set by the DBMS which you do not see and can not handle. Some DBMS even
create indices, but thats another story)
I think it does not matter the start number or the start value that will hold the primary key .
What is important is that they will be represented in the FK of the join tables with the same values that are in the PK of the MAIN table .
A surrogate key can have any values, as long as they are unique. That's what makes it "surrogate" after all - values have no intrinsic meaning on their own, and shouldn't generally even be shown to the user. That being said, you could think about using different seeds, just for testing purposes, as Jon Skeet suggested.
That being said, do you really need to introduce a new (surrogate) key? The existing natural key could actually lead to less1 JOINS, and may be useful for clustering. While there are legitimate uses for surrogate keys, don't do it just becaus it is "fashionable" - always be aware of the tradeoffs you are making and pick the right balance for you concrete needs.
1 It is automatically "propagated" down foreign keys, so you don't need to JOIN the child table to the parent just to get the natural key - natural key is already in the child.
Doesn't matter what int the primary key starts from.
Assuming the codes aren't updated regularly, I don't believe that int will be any faster. It more heavily depends on it being a varchar or of a known size.
I personally always have an field names "Id" as a primary key to a table, defined as an int or a bigInt if necessary.
If the table matches up to an enumerated type then I make sure the Id matches the EnumeratedType id which can be any number - so no it doesn't need to start from 1.
If it doesn't match an enumerated type, then I will usually use an auto-incrementing key starting from 1 but this is not always needed.
Note - that if the number of rows is small, then the difference between indexing on a number and on a varchar will be negligible.
yes, it does'nt matter what integer it start from, it main use is define row uniquely and relationship among other table.
I am starting to think about a basic database driven game(rpg).
I am having trouble sorting out how to save the character, his attributes and his items. For most things where there is only one of them static is fine, but when there are mulitple objects like an inventory for example I am at a bit of a loss.
I decided to put items into a bag object. the bag object can have any where from 5 - 20 slots, each of these slots will reference an item based on unique database ID. So how do I design the bag table.
BagID | Owner | Slot1 | Slot2 | Slot3 | Slot4 ......
or
BagID | Owner | Contents <-varbinary
Any suggestions? I was told once that when database programming, one column one data, but I don't like the idea of Slot1 | Slot2 etc... it just doesn't seem right.
Edit
Did I miss this altogether, and it is rightfully the item that should be referencing the Bag.
ItemID | BagID | Slot | Name | .....
Then when you want to find out what is in a bag you would
Select * from Items where BagID=10
Any suggestions?
STANDARD approach since the invention of relational databases way back in the 60ies by cobb is normalization.
BadId, SlotNr, ItemRef
Finished.
Another table has the items.
Note that OwnerId is missing - this is the BagItemMap table. THe BagTable has BagId, OwnerId and possibly other items (total weight etc.)
This is a standard m:n relationshit. WHen you materialize the objects you ahve a Bag object that has the Items as collection.
The persistence strategy depends on your query requirements. If you are looking for an ability to perform operations on more than one character at a time based on one or more of their attributes (e.g. give an extra life to all three-eyed characters, look up all characters with more than five lives, etc.) then you should save individual attributes into their own columns. If a character is always treated as a BLOB, and you have no issues tying the serialization strategy to the data in RDBMS, then use varbinary.
Hybrid solutions when you store everything as a BLOB, but also make a subset of attributes available in their separate columns, are also possible. In fact, it is very common to include at least some identifying attributes to simplify searches.
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.