I am still new to Grails and Hibernate so if you answer keep in mind I have only used the IDE for 5 days. I have a MYSQL db I am trying to connect to. I set the DB to update as I will need to later on. Then I run the db-reverse-engineer plugin and it auto generates the groovy files in STS for all the tables. When I look at the files I notice in the file a static mapping. I tested one table and created its controller to show all records. It ran perfect. When I looked at the table structure it create 2 new columns "id" and "version". So I noticed the static mapping looks like this:
class TopTen {
Integer ttMlId
Integer ttWeekId
Integer ttAmount
Integer ttRank
static mapping = {
id column: "tt_id"
version false
}
}
When I remove these then it doesn't work at all. I can understand the second line but not why it would create a new column in the DB, and I don't understand what version is or why it puts it there when reverse engineering.
Here is the db table in MySQL database version 5.0.51
DROP TABLE IF EXISTS `top_ten`;
CREATE TABLE `top_ten` (
`tt_id` int(10) unsigned NOT NULL auto_increment,
`tt_ml_id` int(10) unsigned NOT NULL default '0',
`tt_week_id` int(10) unsigned NOT NULL default '601',
`tt_amount` int(10) unsigned NOT NULL default '0',
`tt_rank` int(10) unsigned NOT NULL default '0',
PRIMARY KEY (`tt_id`)
) ENGINE=InnoDB AUTO_INCREMENT=511 DEFAULT CHARSET=latin1;
Hibernate can use optimistic locking and by default it's enabled for all GORM domain classes. But if you don't have a column to use for that in a legacy table or if you want to explicitly disable it for some reason, you can add version false to the mapping block and it won't be active.
Optimistic locking is implemented by comparing the version you think you're editing with the current version at the time the row is updated, and if there's a mismatch it's assumed that there was another user's edit between when you read the row to display the edit form and when you submitted the updated data. It's called optimistic since there's no explicit locking, which is safer but expensive, and it's hoped that two users won't edit the same row at the same time.
If you're seeing a new 'id' column in the database with that mapping block, something is wrong. That should tell GORM that the primary key column has a non-standard column name of 'ttx_id' and use that instead of the 'id' column that it typically uses. Please create a bug report at http://jira.codehaus.org/browse/GRAILSPLUGINS under the Grails-Reverse-Engineer component and include the current database table SQL and the contents of the generated domain class and I'll take a look.
Related
I have one Grails application that has been running for a while. But now I want to change the GORM format and I wonder if there are simple ways to do so, i.e. ways that I don't need to drop existing tables, only modifying my application will do.
To be specific, I used to have one HashSet field that is mapped to varbinary in DB. There are some existing rows in this User table.
public class User{
//irrelevant attributes omitted
HashSet<String> friends=new HashSet<>();
static mapping={
friends sqlType: 'VARBINARY(10000)'
}
}
Now I've changed the field friends to a HashMap<String,Integer>. Now although I still map the field to varchar, Grails throws an exception every time I save an User object:
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
I first suspected that Grails keeps the old converting rule transforming HashSet to varbinary and it wasn't updated. So I tried changing the mapping from varbinary to blob and text, but neither worked.
I'm wondering if there are ways that I keep this column in varbinary in DB while letting Grails know that the attribute is now in HashMap and it should generate new ruls to convert.
Appreciate your insightful advice!
Edit: Im using Grails 2.4.4
There is one way I know of doing this: log into the database server so you have access to the database in a term window. Do this first on your development machine. Look at the relevant columns and see exactly which data types they use. Then, on your development machine, drop those columns and deploy the changed project. The new columns will be created if you've got the gorm set to 'update.' Again inspect the relevant columns and see if there's any way of changing the old columns (alter table...) in your production database to the new columns. You'll have to stop your production server, make the changes, deploy the new project and restart it. If you can't just change the columns you may have to create the new ones, move data over and delete the old ones - all with the application server stopped.
Asp.net mvc 5 Identity 2.0 will create 5 tables automatically when run the mvc project.
Here, my question is why some tables like AspnetUser, it's item 'Id' type defined to string.
The String seems like GUID, but why it doesn't define to guid type instead of using string.
Is it transfer data type from string or do something when quering data ?
I can't figure out why it define to string, but look like guid ?
another table have same problem like AspnetRole, it's item 'UserId', 'RoleId' defined to string too.
Have any idea ?
I'm guessing this is having different reasons.
One reason is the insert performance for Guids, which will get slower and slower after an amount of data (Clustered indexes).
Another reason is the difference of handling Guid in different databases. Microsoft Sql Server has an UniqueIdentifier type that is a Guid, MySql will store them as strings, Oracle stores the raw bytes of a Guid...
I hope this explains a part of your queustion, as not fully :)...
Identity framework not only created for code first approach to be generate database tables with given fields or datatypes. Identity framework can be used against existing database or migrate old asp.net membership provider, or we can use our own table names with extra database fields to store more data on identity tables.
Further more, the Id of the aspnetUser table (that is the User table) used as string because, we can use Guid, integer, long etc. for this field depending on the requirement.
E.g. : If you decided to use integer as Id of the aspnetUser table (User table), then the database field will be auto increment int (or bigInt or etc.) field. But you need to do model binding in order to fulfill entity framework migration requirements.
By default we get Guid inserted into this field when we use out of the box asp.net Identity framework.
When you have defined roles for the registered user, there will be record added into AspnetRole table, this is also completely depending on the fields we defined on the tables as I discussed before. If we decided to use integer as Id of the aspnetUser table, then AspnetRole table fields updated according to the relationship with aspnetUser table fields.
Hope this helps.
I am trying to move an already existing PHP application into grails.
I have created the domains based on the existing database and the code worked perfectly.
The issue arises when I need to add an additional boolean field in my domain.
I am getting the following error.
2014-06-10 16:24:54,146 [localhost-startStop-1] ERROR hbm2ddl.SchemaUpdate - Unsuccessful: alter table entry add expedite tinyint not null
Error |
2014-06-10 16:24:54,163 [localhost-startStop-1] ERROR hbm2ddl.SchemaUpdate - ALTER TABLE only allows columns to be added that can contain nulls, or have a DEFAULT definition specified, or the column being added is an identity or timestamp column, or alternatively if none of the previous conditions are satisfied the table must be empty to allow addition of this column. Column 'expedite' cannot be added to non-empty table 'entry' because it does not satisfy these conditions.
I have tried to specify default values in the variable itself.
boolean expedite = false
I also tried to add default values in static mapping as below:
static mapping = {
table 'entry'
expedite defaultValue: false
version false
}
But still the error crops up. Any idea where I am going wrong? I am using sql server 2012.
Since by default mysql maps boolean field as one bit value, so the value of the boolean field can not be null.
Update your existing records manually by:
update my_table set expedite = 0;
Or you can use grails database migration plugin to generate migrations for you.
Any primitive data types in a domain class gets default value, so if you would have defined your new field like Boolean expedite then it can work with null values.
So always be sure with primitive & non primitive data types.
Looks like sql server uses 0 and 1 instead of TRUE/FALSE. Is this what you are looking for?
https://forum.hibernate.org/viewtopic.php?f=1&t=996345
another person solves like this...
http://codexplo.wordpress.com/2012/06/21/mapping-a-boolean-with-hibernate/
Looks like you just have to create a method in your domain to intercept and convert.
Try use class, not primitive type: Boolean expedite
We have a SQL Server 2008 R2 database with several tables and each table has a number of triggers. On one of the columns, we'll call this Person.Age we have a default value, so that if I don't explicitly supply a value it defaults to "18".
create table PERSON
(
id int IDENTITY(1,1) PRIMARY KEY,
age char(2) DEFAULT '18',
Name char(40),
);
I am using EntityFramework 4.0 (and have also tried 5.0) and Visual Studio 2010, to load and select from the database. Whenever I insert into the table using the following statement, it is inserting a row, but it isn't completing the default value:
var person = new Person
{
Name = "Peter"
};
using (var ctx = new MyEntities())
{
ctx.PERSON.AddObject(person);
ctx.SaveChanges();
}
This will result in a row with a Name of Peter, but the Age will be set to null - and not my default of 18.
When I refresh/load my EDMX file I can only seem to import simple tables and views and there doesn't appear to be an option for importing the properties - although I would have thought this was done by default? Any ideas why the default properties aren't firing?
Also, I have triggers defined in SQL Server so that when a new row is inserted into PERSON, an additional table gets updated. Again this works if I run the SQL direct against the database, but doesn't work if I execute through Visual Studio using EntityFramework.
Thanks,
EF will explicitly set the columns to values you passed. Since, when you created a Person entity, the value for age will be by default set to null EF will send a command in which it will set the column value to null. Set the default value in the ctor if you want to have the default value (otherwise the default value is null for reference properties and default(T) for value type properties (e.g. int)).
The EF designer brings all the columns from the database and create a model with entities that have properties coresponding to the values to the tables and columns it reversed engieneered. You can then go and tweak your model in the designer - for instance you can remove properties you don't want.
I don't know what "does not work" means for you in case of the triggers - it probably depends on your expectation. EF just sends a command to the database. So if you send the same Sql command as the EF sends it should "not work" in the same way. Having said that EF is database agnostic and is not aware of DB magic like triggers. Also the communication is one way only from EF to the DB. So, if you expect that the database notifies the EF about something then it will not work. There are no means for doing this.
Did you ever try to create a ASP.NET MVC Project with Firebird database...I try it, and is difficult..
My problem:
I have working Firebird provider for Visual Studio 2010.
I have correct database with all needed for increasing the id of the tables.
I have created ASP.NET MVC 3 project, with included database, like EDMX file, with entities.
When i try to insert a record into a table, there occurs a problem that says:
FirebirdSql.Data.Common.IscException: violation of PRIMARY or UNIQUE KEY constraint "PK_USERS" on table "USERS"
That means the id of the record that is created is not increased.
I have stored procedures that must generate new id.
My question is:
How to insert record in Firebird data table from ASP.NET?
In Firebird you need to use triggers in combination with sequences (generators) if you want to have auto-increment like behavior. Otherwise you need to make sure that you assign a unique id yourself.
To create the sequence:
CREATE SEQUENCE mytable_id_sq;
To create a trigger for assigning a unique i (on a table called mytable)
set term !! ;
CREATE TRIGGER T1_BI FOR mytable
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
if (NEW.ID is NULL) then NEW.ID = NEXT VALUE FOR mytable_id_sq;
END!!
set term ; !!
This trigger will only assign a generated value if no ID is assigned in the INSERT statement.
See also:
section SEQUENCE (GENERATOR) in the Firebird 2.5 Language Reference and How to create an autoincrement column? (this link talks about generators, the old name of sequences in Firebird).
Your EDMX isn't probably generated properly. Either you have to set the StoreGeneratedPattern manually or use http://blog.cincura.net/230841-generated-primary-key-in-entity-framework-model-from-firebird/ .