jpa eclipselink modify field type - jpa

I'm making my first steps with JPA (eclipselink) developement, and i'm wondering if there's any good practice that may help reflecting changes brought to an entity into the data-base without re-creating the whole data-base.
In my case i have more than 30 entities, some of these are "correctly" defined and are already holding data rows on the data-base, but i've figured out that i made a mistake while defining some other entities by using the int type for the primary key instead of long, and the worst is that some of these entities are mapped by other entities, which means that they're used as foreign keys ... So i'm wondering if there's any "proper" way to deal with this without having to re-create the whole data-base. Re-creating the data-base will force me to re-fill the rows of the already filled tables and waist much time.
Thanks in Advance
George

ints and longs are mapped to a number column in database. Changing the type in the entities won't change anything. You might have to change the precision of the columns in database so that the number is sufficiently large to accept any long value, but doing that is trivial in SQL, using an alter statement.
JPA is just a way to access the database. The database is not supposed to be created by the JPA engine. You may do that, but you're not forced to do that. You may do what you want with your database using SQL, and do whatever you want with your Java code. If they both map together when running the application, it will work.

You can update your current schema automatically to reflect the modifications you've done inthe module by configuring EclipseLink like this:
<property name="eclipselink.ddl-generation" value="create-tables" />
For major modifications to your model it does not guarantee proper update to the schema, but for smaller ones it should work ok.

Related

How to stop EF Core from indexing all foreign keys

As documented in questions like Entity Framework Indexing ALL foreign key columns, EF Core seems to automatically generate an index for every foreign key. This is a sound default for me (let's not get into an opinion war here...), but there are cases where it is just a waste of space and slowing down inserts and updates. How do I prevent it on a case-by-case basis?
I don't want to wholly turn it off, as it does more good than harm; I don't want to have to manually configure it for all those indices I do want. I just want to prevent it on specific FKs.
Related side question: is the fact that these index are automatically created mentioned anywhere in the EF documentation? I can't find it anywhere, which is probably why I can't find how to disable it?
Someone is bound to question why I would want to do this... so in the interest of saving time, the OPer of the linked question gave a great example in a comment:
We have a People table and an Addresses table, for example. The
People.AddressID FK was Indexed by EF but I only ever start from a
People row and search for the Addresses record; I never find an
Addresses row and then search the People.AddressID column for a
matching record.
EF Core has a configuration option to replace one of its services.
I found replacing IConventionSetBuilder to custom one would be a much cleaner approach.
https://giridharprakash.me/2020/02/12/entity-framework-core-override-conventions/
If it is really necessary to avoid the usage of some foreign keys indices - as far as I know (currently) - in .Net Core, it is necessary to remove code that will set the indices in generated migration code file.
Another approach would be to implement a custom migration generator in combination with an attribute or maybe an extension method that will avoid the index creation. You could find more information in this answer for EF6: EF6 preventing not to create Index on Foreign Key. But I'm not sure if it will work in .Net Core too. The approach seems to be bit different, here is a MS doc article that should help.
But, I strongly advise against doing this! I'm against doing this, because you have to modify generated migration files and not because of not using indices for FKs. Like you mentioned in question's comments, in real world scenarios some cases need such approach.
For other people they are not really sure if they have to avoid the usage of indices on FKs and therefor they have to modify migration files:
Before you go that way, I would suggest to implement the application with indices on FKs and would check the performance and space usage. Therefor I would produce a lot test data.
If it really results in performance and space usage issues on a test or QA stage, it's still possible to remove indices in migration files.
Because we already chat about EnsureCreated vs migrations here for completeness further information about EnsureCreated and migrations (even if you don't need it :-)):
MS doc about EnsureCreated() (It will not update your database if you have some model changes - migrations would do it)
interesting too (even if for EF7) EF7 EnsureCreated vs. Migrate Methods
Entity Framework core 2.0 (the latest version available when the question was asked) doesn't have such a mechanism, but EF Core 2.2 just might - in the form of Owned Entity Types.
Namely, since you said:
" I only ever start from a People row and search for the Addresses record; I never find an Addresses row"
Then you may want to make the Address an Owned Entity Type (and especially the variant with 'Storing owned types in separate tables', to match your choice of storing the address information in a separate Addresses table).
The docs of the feature seem to say a matching:
"Owned entities are essentially a part of the owner and cannot exist without it"
By the way, now that the feature is in EF, this may justify why EF always creates the indexes for HasMany/HasOne. It's likely because the Has* relations are meant to be used towards other entities (as opposed to 'value objects') and these, since they have their own identity, are meant to be queried independently and allow accessing other entities they relate to using navigational properties. For such a use case, it would be simply dangerous use such navigation properties without indexes (a few queries could make the database slow down hugely).
There are few caveats here though:
Turning an entity into an owned one doesn't instruct EF only about the index, but rather it instructs to map the model to database in a way that is a bit different (more on this below) but the end effect is in fact free of that extra index on People.
But chances are, this actually might be the better solution for you: this way you also say that no one should query the Address (by not allowing to create a DbSet<T> of that type), minimizing the chance of someone using it to reach the other entities with these costly indexless queries.
As to what the difference is, you'll note that if you make the Address owned by Person, EF will create a PersonId column in the Address table, which is different to your AddressId in the People table (in a sense, lack of the foreign key is a bit of a cheat: an index for querying Person from Address is there, it's just that it's the primary key index of the People table, which was there anyways). But take note that this design is actually rather good - it not only needs one column less (no AddressId in People), but it also guarantees that there's no way to make orphaned Address record that your code will never be able to access.
If you would still like to keep the AddressId column in the Addresses, then there's still one option:
Just choose a name of AddressId for the foreign key in the Addresses table and just "pretend" you don't know that it happens to have the same values as the PersonId :)
If that option isn't funny (e.g. because you can't change your database schema), then you're somewhat out of luck. But do take note that among the Current shortcomings of EF they still list "Instances of owned entity types cannot be shared by multiple owners", while some shortcomings of the previous versions are already listed as addressed. Might be worth watching that space as, it seems to me, resolving that one will probably involve introducing the ability to have your AddressId in the People, because in such a model, for the owned objects to be shared among many entities the foreign keys would need to be sitting with the owning entities to create an association to the same value for each.
in the OnModelCreating override
AFTER the call to
base.OnModelCreating(modelBuilder);
add:
var indexForRemoval = modelBuilder.Entity<You_Table_Entity>().HasIndex(x => x.Column_Index_Is_On).Metadata;
modelBuilder.Entity<You_Table_Entity>().Metadata.RemoveIndex(indexForRemoval);
'''

entity framework and database default values workaround

I have to decide about an important item and I need your help.
I'm facing an huge existing database with a lot of default values on nullable columns.
The team has to build a new MVC4 application on top of it (in fact it is a rewrite of old VB6 application).
I (as a consultant) have 'forced' the use of EF5 to get rid of all stored procedures and migrate to a more modern techology.
Now, after my research, it is clear to me that EF5 doesn't support database default values per default. This is why my inserted records are corrupt (they are inserted because the columns are nullable, but with NULL of course).
Some options came up like using the constructor technique, setting the default values in design on the edmx, or playing around with the xml of the edmx.
Despite, these methods are not usefull for us. Where the constructor technique looks ok for me, it is not feasible to do that for all tables in the DB. I also have a 'njet' from the technical person because he wants to maintain these values on 1 place. Same story for setting the default values in design. The database is also not in our scope (read: as less as possible changes to keep existing applications running).
At this point, I'm not sure it EF is the correct choice for our project.
Is somebody aware of (3th party) tools that can fill in the database default values automatically in the generated xml of the edmx file?
Is there som more info about how this xml is build and if there is a possiblity to interfere in the process?
Is there a good readon why these default values should not be taken? Is this going to change in a later release?
Are there other good practices that can be applied to that problem without having all values dupplicated or a massive workload?
Can I arrange something with my poco generator?
I realize there are already a lot of posts of this topic. Too bad, there is no suitable solution for me since we have already something existing and (with all respect) an old VB6 team that I have to convince.
Thanks for your feedback!

JPA table capitalization inconsistent

We're using a very basic JPA implementation that should create tables consistently from our models.
I believe we're using EclipseLink or TopLink (whichever one is default with the latest Netbeans/Glassfish). The problem is, the tables are created with inconsistent capitaliztion and with the columns out of order. For me, It creates the "User" table as "user", and for other members of my team it creates "USER".
I've tried using the #Table annotation (#Table(name="USer")), but it doesn't work.
How do we get EclipseLink to generate consistent table names? Frankly this seems like a rather amateurish mistake for a framework like this.
Sub-question : the reason this is a problem is because EclipseLink by default has no default way of managing schema/data migrations, as far as I know of. The way we're handling it is by writing a bunch of INSERT INTO's to bootstrap the objects we need in our database, and drop-and-recreating the tables every time the schema changes. I know this is not the best practice for propagating schema changes -- does anyone know how this is typically handled in a standard JPA implementation?
Thanks.
By default EclipseLink uses all upper case for the table name, the class User would be USER.
If you specify an #Table annotation with name="USer", then the table will be created as "USer".
Perhaps you are using your own scripts to create the tables, or you database is changing the case based on the OS or its own settings. What database are you using?
If you enable logging in EclipseLink, it will show the exact DDL that it is executing (if it is executing DDL).
In EclipseLink 2.4 there is also a "create-or-extend-tables" DDL generation option to alter existing tables.
We never found any good answer for this. Luckily, we found a workaround for the ways we were using to update the table, which didn't care about capitalization.

How do I tell EF to ignore columns from my database?

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?

Entity Framework: Ignore Columns

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.