I have a data object (let's say it's called 'Entry') that has a set of potential states that look something like this:
1 - Created
2 - File added
3 - Approved
4 - Invalid
This is represented in the database with a 'Status' table with an autonumber primary key, then a 'StatusId' field in the main table, with the appropriate relationships set up.
In my (custom) data layer, I have the 'Entry' object, and, currently, I also declare an Enum with the states listed above specified. Finally I declare a private instance of this Enum along with the appropriate public property.
In my 'Commit()' method I cast the instance of the Enum to an integer and pass it to an Update stored procedure.
In my static 'GetEntry()' method I will obviously have an integer passed back from the database. I then use the 'Enum.Parse()' method to extract an object which is an instance of my Enum which corresponds to the returned status integer. I cast this to the type of my Enum and assign it to the local private variable.
My question is pretty simple - is this approach appropriate, and if not what alternative, other than just storing the raw integer value (which i'm not necessarily averse to), is better.
My reason for asking is that this all just seems incredibly messy to me, what with all the casting and maintaining two lists of the same set of values. I accept the benefit lies in a better experience for the consumer of the data object, but even so...
Thanks!
We have something familiar in one of our projects.
We have a table containting types of items. These types have an id, in the code we have an enum with the same id's.
The thing is, in the database we don't use autonumber (identity) so we have full control of the id.
And when saving our object we just take the id of the enum to save the object.
I also thought this approach was messy but it's not that bad afterall.
That method seems fine to me.
In the past I've done the same thing but also had a table that contained a row for each member of the enum that table was then the foreign key for any table that used the enum value, just so someone reading the database could understand what each status was without having to see the actual enum.
for example if I had an enum like
enum status
{
Active,
Deleted,
Inactive
}
I would have a table called status that would have the following records
ID Name
0 Active
1 Deleted
2 Inactive
That table would then be the foreign key to any tables that used that enum.
Yup this is fine!
PLEASE always explicitly set the values like this. That way if someone ever goes to add something they'll realize the values are important and shouldn't be messed with.
enum status
{
Active = 1,
Deleted = 2,
Inactive = 3
}
If you're passing the value around via WCF I'd recommend adding
NULL = 0
Otherwise if you try to serialize a 0 coming from the database you'll get a horrible error and it'll take you forever to debug.
the database lookup table is necessary; the programmatic enum is convenient to avoid having 'magic numbers' in the code
if your code does not need to manipulate the status, however, then the enum is unnecessary
I do this approach with Enums all the time. If it is a simple item like status that is not expected to change ever I prefer the Enum. The parsing and casting is a very low impact operation.
I have been doing this successfully with Linq to Sql for sometime now with no issues. Linq will actually convert from Enum to int and back automatically.
Code is more than just about speed but readability. Enums make code readable.
To answer your question directly this is a very valid apporach.
If your code requires setting known "Status" values (which you've defined in your enum), then it's probably also a requirement that those "Status" values exist in the database. Since they must exist you should also have control over the Status_ID assigned to each of those values.
Drop the identity and just explicitly set the lookup value IDs.
Related
I have a entity Person which has an enum "State" with the values "new, accepted, blocked". Entity framework code first creates a field on the person table with an 1 for new, 2 for accepted and 3 for blocked. That's fine as long I'm in code view. Whenever I need to fix a db for what ever reason "1" doesn't mean anything, I need to look up first in code what 1 means for that enum.
My first idea was to simply make a separate table for those enums and make the enum a class with an id and the enum. But then I get another (unnecessary) join on each query where the enum is needed. I want to avoid that.
So, is it possible to have a separate table for the enum with fix ids so that the id of the enum table is equal to the value of the enum and still have entity framework using the normal approach where it just uses the value of the enum as saved value? I got stuck when I wanted to use a foreign key to enforce reference integrity to make sure no one forgets to update the enum table. Entity framework can't set this foreign key because it does not know the table and when it knows it, it makes relationships what I also don't want because of the joins..
Some years passed by, I learned a lot. So if anyone ever sees that question and wonders, here is what I normally do as of today.
So, unless there is a special reason to actually have a table for code (enum) values (like when you have additional data instead of just a code) I just put the enum value into the table that uses the enum. e.g. in the example above the person table gets a integer column for the enum value. In C# with entity framework I use it like this:
// write to db:
personEntity.PersonState = (int)State.New;
// read from db, e.g.:
if (personEntity.PersonState == (int)State.New {
// logic here
}
// or if you need the value as enum:
State personState = (State)personEntity.PersonState;
I found that is a good and easy approach for most cases.
Try code below
Module Module1
Enum MyEnum
a = 1
b
c
d
e
f = 100
End Enum
Sub Main()
Dim x As MyEnum = MyEnum.d
Console.WriteLine(x)
Console.ReadLine()
End Sub
End Module
I am designing a DAL.dll for a web application. The Scenario is that on the web user gets the entity and modifies some fields and click save. My problem is that how to make sure only the modifield field to be saved.
For Example, an entity:
public class POCO{
public int POCOID {get;set;}
public string StringField {get;set;}
public int IntField {get;set;}
}
and my update interface
//rows affected
int update (POCO entity);
When only the IntField is modified, because StringField is null, so I can ignore it. However, when only the StringField is modifield, because IntField is 0 - default(int), I cannot determine if it should be ignored or not.
Some limitations:
1. stateless, no session. so cannot use "get and update", context, etc.
2. to be consistent to data model, cannot use nullable "int?"
Just a tip, if negtive number is not allow in your business requirement, you can use -1 to indicate this value does not apply.
I don't really understand how you want to work stateless, but update only changed properties. It will never work when stateless, since you will need a before-after comparison, or anything else to track changes (like events on property setters). Special "virgin" values are not a good solution, since I think your user wants to see the actual IntField value.
Also make your database consistent with your application data - if you have standard, not-nullable int values, make the DB column int not null default 0! It is really a pain to have a database value which can't be represented by the program, so that the software "magically" turns DB null into 0. If you have a not-nullable int in your application, you can't distinguish between DB null and zero, or you have to add a property like bool IsIntFieldNull (no good!).
To reference a common Object-relational mapper, NHibernate: it has an option called "dynamic-update" where only changed properties/columns are updated. This requires, however, a before-after check and stateful sessions, and there's debate on whether it helps performance, since sending the same DB query every time (with different parameter values) is better than sending multiple different queries - opposed to unneccessary updates and network load. By default, NHibernate updates the whole row, after checking if any change has been done. If you only have ID, StringField and IntField, dynamic-update instead of full-row update might in fact be a good solution.
Mapping nullable DB columns to not-nullable application data types, such as int, is a common mistake when implementing NHibernate, since it creates self-changing DAL objects.
However, when working with ORM or writing your own DAL, make sure you have proper database knowledge!
Options
Many ORMs (Object-relational mapping) provide this type of functionality. You define your object to work with say "Entity Framework" or "NHibernate". These ORM's take care of reading and writing to the database. Internally, they have their own mechanisms to keep track of what has been modified.
Look into Delta<\T> (right now it's an ODATA thing, so it may not be useful to use, but you can learn from it)
Make your own. Have some type of base class that all your other objects inherit from, and somehow when you set fields it records those somewhere else.
I highly recommend not relying on null or magic numbers (-1) to keep track of this. You will create a nightmare for yourself.
Let' say I have a TestClass in my C# app with property A and property B.
I change the value of B by my code, I leave property A unchanged.
I update TestClass in database by SimpleRepository's Update method.
As I see it updates also property A value in the database.
It is easy to test: I change value A in my database outside my app ('by hand'), then I make the update from my app. Value of property A changes back to its value according to TestClass's state in my app.
So, my question: is it possible to make updates only to some properties, not for the whole class by SimpleRepository? Are there some 'IgnoreFields' possibilities?
What you need is optimistic concurrency on your UPDATE statement, not to exclude certain fields. In short what that means is when updating a table, a WHERE clause is appended to your UPDATE statement that ensures the values of the fields in the row are in fact what they were when the last SELECT was run.
So, let's assume in your example I selected some data and the values for A and B were 1 and 2 respectively. Now let's assume I wanted to update B (below statement is just an example):
UPDATE TestClass SET B = '3' WHERE Id = 1;
However, instead of running that statement (because there's no concurrency there), let's run this one:
UPDATE TestClass SET B = '3' WHERE Id = 1 AND A = '1' AND B = '2';
That statement now ensures the record hasn't been changed by anybody.
However, at the moment it doesn't appear that Subsonic's SimpleRepository supports any type of concurrency and so that's going to be a major downfall. If you're looking for a very straight forward repository library, where you can use POCO's, I would recommend Dapper. In fact, Dapper is used by Stackoverflow. It's extremely fast and will easily allow you to build in concurrency into your update statements because you send down parameterized SQL statements, simple.
This Stackoverflow article is an overall article on how to use Dapper for all CRUD ops.
This Stackoverflow article shows how to perform inserts and updates with Dapper.
NOTE: with Dapper you could actually do what you're wanting to as well because you send down basic SQL statements, but I just wouldn't recommend not using concurrency.
Don't call the update method on the DataObject for such cases, you are basically indicating that the object has been changed and needs to be updated in the DB.
So subsonic will generate a query like
UPDATE TestClass SET A ='', B='', ModifiedOn = 'DateHere' WHERE PrimaryKey = ID
to change only the property B you need to consturct the UPDATE query manually.
have a look at the Subsonic.Update class.
Ideally you shouldn't be forming a new instance of the data object manually, if you do so make sure
the values are copied from the object retured from the Subsonic.Select query.
So when you update the value of even only one property all other properties will hold their own value from DB rather than a default value depending on the type of the property.
According to REST philosophy, a PUT operation should (taken from Wikipedia):
PUT http://example.com/resources/142
Update the address member of the collection, or if it doesn't exist, create it.
NHibernate seems to have two ways of dealing with entity IDs:
Auto-generate an ID, regardless of what value the user set.
Use the ID assigned by the user, but lose all auto-generation capabilities.
The problem here with a PUT operation is the part about creating the entity if it doesn't exist. My assumption is that if you PUT a resource that doesn't exist, it will create it with the same ID as specified by the URL (such as 142 if we use the above example). However, NHibernate doesn't allow you to set the ID if it's auto-generated.
So my question is, is there a way to get NHibernate to auto-generate an ID if the entity doesn't have one (or has the default value for the ID type, for example 0 for ints), but also save the entity with the ID that the user set?
Generally its a bad idea to use assigned ids.
The situation that you have is closer to the thing called NaturalId. You should use it I think. You will need to have two different properties, one for databases primary key, and second as a id that is visible to users.
Say my database tables have columns like UserType, SalesType, etc.
Should I have database tables with UserTypeID, userTypeName or should I just create a C# enumeration?
What's wrong with both? If value's are user-defined or changing, definitely enum will not be suitable.
If values are strictly non-changing (such as gender), you can have them as enums for ease of reference in the application and also in the DB as separate table to enforce foreign keys and as a reference.
It depends. I listed a few pros and cons for each approach below. In general, I strongly prefer enums if the application needs to use a value to make decisions. As Mehdrad mentioned, you can use both approaches but it requires extra effort to keep the lists in sync.
Lookup tables:
Referential integrity can be enforced
through foreign keys
Easy to add or remove existing values
Table can be extended to add additional fields (active flag, etc.)
Requires additional class if using business objects
Easy to use value and description in reports
Enum:
Check constraint can enforce data integrity
Best choice if code needs to use value for branching (e.g. x == SalesType.Web vs. x == "WEB")
Requires software release to change values
Cannot display description in SQL queries (without CASE)
Enum may not be appropriate for display in UI (there are workarounds)
In my projects, I use my application dbscript to generate C# consts from database, so code always matches db values.
Of course, you only need to have C# enums if your code does something specific depending on the value of the Type field.
If the list is stable enough to use an enum, then I would use an enum in your code plus a table in the database (make it a foreign key for data consistency).