I'm building my EF (v4.0.30319) data model from my SQL Server database. Each table has Created and Updated fields populated via database triggers.
This database is the backend of a ASP.NET Web API application and I recently discovered a problem. The problem is, since the Created and Updated fields are not populated in the model passed into the api endpoint, they are written to the database as NULL. This overwrites any values already in the database for those properties.
I discovered I can edit the EF data model and just delete those two columns from the entity. It works and the datetimes are not overwritten with NULL. But this leads to another, less serious but more annoying, problem... my data model has a bunch of tables that contain these properties and all the tables need to be updated by removing these two columns.
Is there a way to tell EF to ignore certain columns in entities across the entire data model without manually deleting them?
As far as I know, no. Generating the model from the database is going to always create all of the fields from the database table. Well, as long as it has a primary key it will.
It is possible to only update the fields that you want i.e. don't include the "Created" and "Updated" fields in your create and update methods. I'd have to say though, that I'd think it'd be better if those fields didn't even exist on the model at that point. You may at one point see those fields on the model and not remember that they won't get persisted to the DB.
You may want to look into just inserting the datetimes into those fields when you call your create() and update() methods. Then you could just ditch the triggers. You'd obviously want to use a class library for all of your database operations so this functionality would be in one place. To keep it nice and neat, you know?
Related
We have an entity and a corresponding table in the database with one additional column which contains digested hash of the entity fields, calculated each time programmatically in application. Entity has associations with two additional tables/entities which fields also take part in hashing.
Now a decision was made to get rid of one of the fields from the main entity (boolean flag) and exclude it from hashing, since it makes two otherwise identical entities get different hashes when one entity has its flag set to true, while other is false. Since hashes are different both entities get stored in the database, which is not what we want.
Removing the field is simple, but we also need to re-calculate hashes for entities which have been already stored in the database. Since there might be duplicates, we also need to get rid of one of two duplicated entries. This whole operation must be done once after migration.
The stack we use is Quarkus, Flyway, Hibernate with Panache, and PostgreSQL. I have tried to use Flyway callbacks with Event.AFTER_MIGRATE to get all existing entities from the db, but I can't use Panache since its not initialised yet by the time callback hits. Using plain java.sql.* Connection and Statement is pretty cumbersome, cause I need to fetch data from 3 tables, create entity from all of the fields, re-calculate hash and put it back, while taking care of possible conflicts. Another option would be to create a new REST API endpoint specifically for the job which the client will have to call after app has booted, but somehow I don't feel that that is the best solution.
How do you tackle this kind of a situation?
currently I am working at a project which requires to be backwards compatible with (non-EF) databases, but also want to create a new database from model.
For this task I save the current schema somewhere (in XML form) and update the databases with raw sql update steps, until they match the schema, which is working fine.
Also, the modelBuilder matches the schema (as in, my algorithm finds no difference between the newly created database by context.Database.Create() and my saved schema) currently.
Since the schema will most likely change in later stages of development, I do have to support two ways to create an Up-to-date database and was wondering if I could combine these two - since now I have to update the saved target schema, create the update steps AND update my modelBuilder so that is creates exactly the database I need - which would be quite a tedious task.
So since there is probably no way to "translate" my schema to modelBuilder entries and because there is more not mapped information in my POCO classes (which prohibits the approach of updating a correct database and update my classes database first) the only (visible to me) way would be to somehow gather the CREATE TABLE statements a context would create when I call Database.Create() which I can use to update my schema and the update steps accordingly.
I know quite sure I can do the same by logging the context while calling the Create() method, however - this will take quite some time, will issue some queries I do not need and will create a dump database I have to get rid of afterwards each time I update my model.
So I was wondering if there was a way to inspect the modelBuilder (or the context, of course) and somehow see what the tables would look like it maps to.
I'd like to know what is the best practice to track and/or persist changes over time if I use EF. I'd like to get started with EF for a new project. What I need is a kind of change history.
That's how I did it before: If a record was created it was saved with an ID and with the same ID as InvariantID. If the record was updated i marked it as deleted and created a new record with the new values and a new ID but the same InvariantID. Like this I always had my current record but a history of changes as well.
This works perfectly fine for my scenarios. The amount of historical records is not an issue because I use this usually only for data that's not changing very often.
Is this build in EF somehow or what's the best way to get this behavior for EF?
No it is not build into EF and it will not work this way. I even don't think that it is a good approach on the database level because it makes referential integrity very complex.
With EF this will work only if you use following approach:
You will use conditional mapping for your entity - condition will be IsDeleted = 0. It will ensure that only non deleted entities will be used in queries.
You will have mapped stored procedure for delete operation to correctly set IsDeleted = 1 instead of really deleting the record
You will have to manually call DeleteObject to delete your record and after that you will insert new record - the reason is that EF is not able to deal with scenario where entity change its PK value during update.
Your entities will not be able to participate in relations unless you manually rebuild referential integrity with some other stored procedure
You will need stored procedure to query historical (deleted) records
I've been scratching my head over this for over a week now and haven't gotten anywhere :( We have an existing legacy DB that I'm trying to model my entities against. The tables are extremely bloated and we do not have enough bandwidth to create new, optimized tables. So I'm having to work with what we already have. However, I do not want to use all the redundant columns that are exposed by the DB. My initial plan was to use Views in my Model but that is looking to be equally hairy with very little documentation around.
Now, what would be the best way to go about creating a Model with just a select few columns? All I need is a bunch of read-only entities; so if there is a way to ignore non-nullable columns from the schema, I'd be all set. I was planning on making use of POCOs else I'd have to create my own mappings I reckon.
UPDATE: By POCOs, I mean I'd like to use the ADO.NET POCO Entity Generator.
What about creating views in the DB, and only importing the views into the model?
Well, if you need only a bunch of entities and if they won't change a lot during time, than I would just pick the tables you need, generate the entities with the normal wizard and all collumns, and than delete all not needed collumns manually in the model designer.
add the table to your EF, and just delete the properties you don't want. it just won't map those DB fields.
I have a database that I wish to build an EF model from, however I do not want to include certain columns from the database as the columns concerned are maintained exclusively on the server and should not be manipulated by any application.
Both of the columns are DateTime (if this makes any difference), one of the columns is nullable and is maintained by a trigger on updates and the other is not nullable and set using a default value in the table definition.
I guess I am looking for something like the "Server Generated" option in Linq2Sql; but I cannot find such an option.
Can anybody tell me how to work around this?
Caveat:
I have been trying to introduce business object modelling at my place of work for some years and it has always been rejected because of the amount of additional code that has to be hand-cranked. EF is currently being seen as a viable solution because of the designer and code generation therefore any option that involves hand-cranking the XML will only turn the rest of my colleagues away from EF. I am therefore looking for something that can be done either using the designer or using code.
EDIT:
I guess that what I am looking for here is either...
(a) a way to create the model without EF referencing the columns in the store (ssdl) and therefore not looking to manipulate it in any way
(b) a way to programatically set the "StoreGeneratedPattern" attribute against the property when I create the ObjectContext (the easy answer is to manually manipulate this in the .ssdl, but this would then be overwritten if I refreshed the model from the database and I cannot go down the route where the .csdl, .msl & .ssdl are hand-cranked).
Can you do this with the Entity Framework? Yes; it's easy. Can you do this with the Entity Framework designer? Unfortunately, that is much harder.
The problem you're having is that the column exists in the storage schema (SSDL) in your EDMX. Removing the column with the GUI designer simply removes it from the client schema, not the mapping or the storage schema. However, it's simple enough to go into the EDMX and remove it. Having done that, you can also remove it from the mapping in the client schema portions of the EDMX, and the entity framework will longer complain that it is unmapped.
Problem solved, right?
Well, no. When you use the GUI designer to update the EDMX from the database, the storage schema is thrown away and re-generated. So your column will come back. As far as I know, there is no way to tell the GUI designer to never map a particular column. So you will have to re-do this every time you update with the GUI designer. Fortunately, the EDMX is XML, so you can do this with a XML transform, LINQ, or the XML tool of your choice.
Can you not create a view with the columns you need and import it through entity function wizard and map it to your entities?
You could modify the text template to ignore these columns when generating your entity classes. For example if you added "IGNORE" to the documentation summary, you could modify the template to ignore them by replacing;
Dim simpleProperties as IEnumerable(Of EdmProperty) = typeMapper.GetSimpleProperties(entity)
with;
Dim simpleProperties as IEnumerable(Of EdmProperty) = typeMapper.GetSimpleProperties(entity).Where(Function(p) p.Documentation is nothing orelse p.Documentation.Summary.IndexOf("IGNORE")<0)
Right click on the field in the graphical representation and choose delete. Ive found that sometimes you will get errors when you make a lot of changes to the modeling at once and start to lose track of your changes. Your best bet might be to rebuild the EF generated model.
Keep in mind that when you "update from the database", that old fields on the generated models will not be removed, you will have to remove them manually. For example if you renamed DateField1 to DateField2 in your database, and then you "Update Model from Database", you will now see both DateField1 and DateField2 on the resultant model. This can be a cause of errors.
Do you not want the column to appear in the model at all?
Try selecting the column in the Designer view and hitting the delete key.
Edit
You could make the setter for the property private. Then your app won't be able to modify the value.
Timestamp is a different data type than DateTime. Timestamp seems to be recognized as an attribute the engine manages, much like an identity attribute. You can't "update" a timestamp attribute. Hence, the EDM can manage it correctly (just as it does an identity).
In EDMX designer, select the property and set StoreGeneratedPattern to Computed.