Use separate Enum Table(entity) in Entity Framework without join - c#

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
​

Related

EF CodeFirst mapping enum with custom value mapping

I need to create an application that is compatible with various legacy database systems.
So, the database exists, but I still want to use code first to be independent from whatever database is used as datastore. For each deployment, I intend to create a "mapping" library containing the correct FluentAPI mappings of the entities to the database.
I'm using EF6.
I don't want code first to alter anything in the database structure automagically, so I use
Database.SetInitializer<mycontext>(null);
Now I'm stuck on following issue:
my code defines an enum Gender, which is used as a property in the Person entity
public enum Gender
{
M = 1,
F = 2
}
However, in one of the legacy databases, the values are the other way around. The table "Gender" exists, and the lookup data in that table is ID 1 = female, ID 2 = male.
The Person table has a "FK Gender ID" column.
How would I configure through Fluent API the mapping of the Gender property of my Person entity, to the Person table in the legacy database table.
modelbuilder.Entity<Person>()
.Property(c => c.Gender)
.HasColumnName("FK Gender ID") //--> and how to "inverse" these values here ?
Is this possible with Fluent API, and if not, is there a workaround ?
Thanks.
I don't think that something you are trying to do is possible. For simplicity you should consider changing your code to match what you have in your database. If you cannot do that here is what you can do. Define an enum type (something like GenderDb or something). Ideally no one should even see this enum. Then create private properties of GenderDb type and map them to database columns (I believe in EF you can map columns to private properties). Again the properties are private so that no one can see them. Then add public properties of the Gender type on the entities that have the private GenderDb properties. The public properties should be configured as not mapped/ignored. Now implement the setter and the getter of the public properties so that it converts the value accordingly (i.e. setter converts the Gender enum to GenderDb and sets the private property, getter reads the private property and converts GenderDb to Gender).
(Yes you could get away with just one enum type if you like to receive phone calls at 2 am)

Fine Grained CRUD with Subsonic's SimpleRepository

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.

Generics and database - a design issue

The situation is that I have a table that models an entity. This entity has a number of properties (each identified by a column in the table). The thing is that in the future I'd need to add new properties or remove some properties. The problem is how to model both the database and the corresponding code (using C#) so that when such an occasion appears it would be very easy to just "have" a new property.
In the beginning there was only one property so I had one column. I defined the corresponding property in the class, with the appropriate type and name, then created stored procedures to read it and update it. Then came the second property, quickly copy-pasted, changed name and type and a bit of SQL and there it was. Obviously this is not a suitable model going forward. By this time some of you might suggest an ORM (EF or another) because this will generate the SQL and code automatically but for now this is not an option for me.
I thought of having only one procedure for reading one property (by property name) and another one to update it (by name and value) then some general procedures for reading a bunch or all properties for an entity in the same statement. This may sound easy in C# if you consider using generics but the database doesn't know generics so it's not possible to have a strong typed solution.
I would like to have a solution that's "as strongly-typed as possible" so I don't need to do a lot of casting and parsing. I would define the available properties in code so you don't go guessing what you have available and use magic strings and the like. Then the process of adding a new property in the system would only mean adding a new column to the table and adding a new property "definition" in code (e.g. in an enum).
It sounds like you want to do this:
MyObj x = new MyObj();
x.SomeProperty = 10;
You have a table created for that, but you dont want to keep altering that table when you add
x.AnotherProperty = "Some String";
You need to normalize the table data like so:
-> BaseTable
RecordId, Col1, Col2, Col3
-> BaseTableProperty
PropertyId, Name
-> BaseTableValue
ValueId, RecordId, PropertyId, Value
Your class would look like so:
public class MyObj
{
public int Id { get; set; }
public int SomeProperty { get; set; }
public string AnotherProperty { get; set; }
}
When you create your object from your DL, you enumerate the record set. You then write code once that inspect the property as the same name as your configuration (BaseTableProperty.Name == MyObj.<PropertyName> - and then attempt the type cast to that type as you enumerate the record set.
Then, you simply add another property to your object, another record to the database in BaseTableProperty, and then you can store values for that guy in BaseTableValue.
Example:
RecordId
========
1
PropertyId Name
========== ====
1 SomeProperty
ValueId RecordId PropertyId Value
======= ======== ========== =====
1 1 1 100
You have two result sets, one for basic data, and one joined from the Property and Value tables. As you enumerate each record, you see a Name of SomeProperty - does typeof(MyObj).GetProperty("SomeProperty") exist? Yes? What it it's data type? int? Ok, then try to convert "100" to int by setting the property:
propertyInfo.SetValue(myNewObjInstance, Convert.ChangeType(dbValue, propertyInfo.PropertyType), null);
For each property.
Even if you said you cannot use them, that is what most ORM do. Depending on which one you use (or even create if it's a learning experience), they will greatly vary in complexity and performance. If you prefer a light weight ORM, check Dapper.Net. It makes use of generics as well, so you can check the code, see how it works, and create your own solution if needed.

Linq2sql inheritance cast

I'm usign inheritance in linq2sql and have entites Supplier and Buyer that inherits from Client. I need to be able "upgrade" a Buyer to a Supplier.
I've tried:
Client client = ClientMethods.ValidateId<Client>(clientId);
client.ClientTypeId = ClientMethods.CLIENT_TYPE_SUPPLIER;
db.SubmitChanges();
But get "Not allowed: Inheritance discriminator change from '1' to '2' would change type from 'Buyer' to 'Supplier'."
The only solution I can find is to do this without linq2sql and write a SP??
I am wondering why you even have the two different sub classes if it is a natural situation that you want to change from one type to the other. I think that you should refactor what you have and make the buyer and supplier one entity. Then if you have behavior that should be different based on whether or not the client is a buyer or supplier I would extract that into a seperate object which you can set or add to the client.
i just had the same problem, and solved*) it by doubling the discriminator field into one computed column that is actually used as discriminator value and an integer column storing the value ...
*) - one of the famous solutions that could have nasty side effects, so be warned
Perhaps, try to create a new supplier by populating the buyer's properties' value?

Using Enum for a data layer object's 'status' in C#

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.

Categories

Resources