How to map two tables and not make any changes when mapping legacy database tables in Grails? - database

I'm new to Grails and mapping and I have something that looks like this.
I have two domain classes and I need to make a relationship between them, and when the relationship is done that no changes would be made to existing tables from my PostgreSQL database.
class Insurance{
Integer id
String osg_name
String osg_logo
String osg_email
String osg_link
static hasMany = [ insurancePackage: InsurancePackage]
static constraints = {
id(blank: false)
osg_name (blank: false, size: 0..155)
osg_logo (size: 0..155)
osg_email (blank: false, size: 0..100)
osg_link (size: 0..155)
}
static mapping = {
table name: "insurance", schema: "common"
version false
id generator :'identity', column :'osg_id', type:'integer'
}
}
class InsurancePackage{
Integer id
Integer osg_id
String osgp_comment
Integer tpo_id
String osgp_link
String osgp_label
//static belongsTo = Insurance
static belongsTo = [insurance: Insurance]
static constraints = {
id(blank: false)
osg_id (blank: false)
osgp_comment (blank: false, size: 0..500)
tpo_id (blank: false,)
osgp_link (blank: false, size: 0..155)
osgp_label (blank: false, size: 0..10)
}
static mapping = {
table name: "insurance_package", schema: 'common'
version false
id generator :'identity', column :'osgp_id', type:'integer'
}
}
This is the error that I'm getting
Error 2015-07-16 13:38:49,845 [localhost-startStop-1] ERROR hbm2ddl.SchemaUpdate - Unsuccessful: alter table revoco.insurance_package add column insurance_id int4 not null
| Error 2015-07-16 13:38:49,845 [localhost-startStop-1] ERROR hbm2ddl.SchemaUpdate - ERROR: column "insurance_id " contains null values
| Error 2015-07-16 13:38:49,845 [localhost-startStop-1] ERROR hbm2ddl.SchemaUpdate - Unsuccessful: alter table revoco.insurance_package add constraint FK684953517A89512C foreign key (insurance_id ) references revoco.insurance
| Error 2015-07-16 13:38:49,845 [localhost-startStop-1] ERROR hbm2ddl.SchemaUpdate - ERROR: column "insurance_id " referenced in foreign key constraint does not exist
So I cant connect the two tables and I'm getting the same error, for some reason Grails are trying to find insurance_id but that is not defined in classes and they are trying to alter my tables and I don't want that to happen.

You are created a new column in the insurance_package table that holds a foreign key to the insurance table. (hasMany and belongsTo --> one-to-many)
The problem here is that the column has a NOT NULL contraint by default but the table appears to have already data in it.
The question is now: What to do with the data already contained in the table. Grails wants to set the NOT NULL constraint but can't because there are already in there and because you have just created the column and the values are NULL
You have 3 options depending on your use case:
delete the values already contained in the table (maybe not wanted)
Go in your db management tool and set a foreign key for those rows and then restart the server. The error should disappear
set the constraint for your insurance reference (belongsTo) in your "InsurancePackage" object to be nullable:true

Related

Django migrate column is not the same data type as referencing column

I have the below model which is an existing DB model and through Django's inspectdb management command the below model is created.
class ExistingLegacyModel(models.Model):
period = models.TextField(db_column="Period", blank=True, null=True)
key = models.AutoField(db_column="OutlookKey", primary_key=True)
class Meta:
managed = False
db_table = "table_name"
and currently, I'm trying to create a model with a field foreign key reference to the existing legacy DB model
class TestModel(models.Model):
period = models.ForeignKey(
ExistingLegacyModel,
on_delete=models.CASCADE,
db_column="OutlookKey",
)
so when I run the makemigrations command the migration file is successfully getting created with no issue. below is the migration file content.
class Migration(migrations.Migration):
initial = True
dependencies = [
('historical', '0011_phoenixcontractprice'),
]
operations = [
migrations.CreateModel(
name='TestModel',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('period', models.ForeignKey(db_column='OutlookKey', on_delete=django.db.models.deletion.CASCADE, to='app.ExistingLegacyModel')),
],
),
]
so now when i run the migrate command now, it is failing and giving the below error.
django.db.utils.ProgrammingError: ('42000', "[42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Column 'table_name.OutlookKey' is not the same data type as referencing column 'version_testmodel.OutlookKey' in foreign key 'version_testmodel_OutlookKey_eb16c31c_fk_table_name_OutlookKey'. (1778) (SQLExecDirectW); [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Could not create constraint or index. See previous errors. (1750)")
I'm stuck with this issue for the past couple of days and I searched all over the internet but didn't get any resolution. I found a couple of StackOverflow questions that are very similar to my issue, but those questions are also unanswered.
Django - Migration foreign key field type not matching current type
Django 3.2 update AutoField to BigAutoField backward compatibility with foreign key relations
I'm currently using Django 3.2.13 and mssql-django to connect to the MSSQL database.
Any help on this will be highly appreciated! Thank you in advance.
UPDATE 1
I ran the sqlmigrate command for the initial migration. So for the period column, it is creating the table with a foreign key field with big int [OutlookKey] bigint NOT NULL whereas the existing legacy model has a normal integer field.
ALTER TABLE [<app>_<model>] ADD CONSTRAINT [<app>_<model>_OutlookKey_3505d410_fk_<existing_legacy_table>_OutlookKey] FOREIGN KEY ([OutlookKey]) REFERENCES [<existing_legacy_table>] ([OutlookKey]);

How to figure out what exact entity resulted in DbContext.SaveChanges FK conflict failure

With Entity Framework Core (in case it matters, I'm using version 2.2), I update a number of entities in the DB context and call SaveChanges. In case saving fails because of the foreign key issue, I can't figure out what exact entities have foreign key issues. Is it possible to figure this out?
When Foreign Key conflict happens, SQL Server returns an error with code 547 and text The UPDATE statement conflicted with the FOREIGN KEY constraint "<Constraint>". The conflict occurred in database "<Database name>", table "<Table name>", column '<Column name>' without reference to exact invalid rows.
I have looked at DbUpdateException properties, but no luck:
var dbUpdateEx = ex as DbUpdateException;
var erroredEntries = dbUpdateEx.Entries;
// The documentation says that Entries property "Gets the entries that were involved in the error",
// but in my case it's always empty.
Also, I have tried validating entities manually before save, but such validation does not find FK conflicts. Code sample:
var valProvider = new ValidationDbContextServiceProvider(dbContext);
var valContext = new ValidationContext(entity, valProvider, null);
var entityErrors = new List<ValidationResult>();
var result = Validator.TryValidateObject(entity, valContext, entityErrors, true);
When I save more than 100 records and the save fails because of FK conflict in a single entity, it's quite frustrating to look for this single invalid record by hand.

MS-SQL server throws error when two foreign keys are set on same table using GORM

I am doing database migrations using GORM. So I define structs and run them through GORM's AutoMigrate function.
type Person struct {
ID string `gorm:"type:varchar(36);primary_key"`
}
err := db.Table("persons").AutoMigrate(&Person{}).Error
type Address struct {
ID string `gorm:"type:varchar(36);primary_key"`
PersonID string `gorm:"column:person_id;type:varchar(36);NOT NULL"`
}
err = db.AutoMigrate(&Address{}).Error
err = db.Model(&Address{}).AddForeignKey("person_id", "persons(id)", "NO ACTION", "CASCADE").Error
type Contact struct {
ID string `gorm:"type:varchar(36);primary_key"`
AddressID null.String `gorm:"column:address_id;type:varchar(36);NOT NULL"`
PersonID string `gorm:"column:person_id;type:varchar(36);NOT NULL"`
}
err = db.AutoMigrate(&Contact{}).Error
err = db.Model(&Contact{}).AddForeignKey("address_id", "addresses(id)", "NO ACTION", "CASCADE").Error
err = db.Model(&Contact{}).AddForeignKey("person_id", "persons(id)", "NO ACTION", "CASCADE").Error
In the above code, which ever is the second call to the AddForeignKey function on Contacts table is giving error :
mssql: Could not create constraint or index. See previous errors.
Even if I move person_id foreign key above address_id foreign key, then address_id foreign key fails.
I am running MS-SQL server using latest docker container setup(microsoft/mssql-server-linux:latest). Is this something regarding naming of constraint. If yes, then how can we set using GORM? Everything works fine with My-SQL.
It would be really helpful if I get a solution. I cannot run raw queries. Migrations have to be done using GORM only.
Thank You
Multiple foreignkeys can't have 'no action', 'cascade' on the same table. If u use no action, no action u can but u have to handle deletion and updating your self. What I usually do is turn on logmode and copy paste the log sql statement into SQL. This will give u a more clear error.

How to make the 'public' schema default in a Scala Play project that uses PostgreSQL?

I am not sure if my issue connecting to the Scala Play 2.5.x Framework or to PostgreSQL so I am going to describe my setup.
I am using the Play 2.5.6 with Scala and PostgreSQL 9.5.4-2 from the BigSQL Sandboxes. I use the Play Framework default evolution package to manage the DB versions.
I created a new database in BigSQL Sandbox's PGSQL and PGSQL created a default schema called public. I use this schema for development.
I would like to create a table with the following script (1.sql in DB evolution config):
# Initialize the database
# --- !Ups
CREATE TABLE user (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
email TEXT NOT NULL,
creation_date TIMESTAMP NOT NULL
);
# --- !Downs
DROP TABLE user;
Besides that I would like to read the table with a code like this:
val resultSet = statement.executeQuery("SELECT id, name, email FROM public.user WHERE id=" + id.toString)
I got an error if I would like to execute any of the mentioned code or even if I use the CREATE TABLE... code in pgadmin. The issue is with the user table name. If I prefix it with public (i.e. public.user) everything works fine.
My questions are:
Is it normal to prefix the table name with the schema name every time? It seems to odd to me.
How can I make the public schema a default option so I do not have to qualify the table name? (e.g. CREATE TABLE user (...); will not throw an error)
I tried the following:
I set the search_path for my user: ALTER USER my_user SET search_path to public;
I set the search_path for my database: ALTER database "my_database" SET search_path TO my_schema;
search_path correctly shows this: "$user",public
I got the following errors:
In Play: p.a.d.e.DefaultEvolutionsApi - ERROR: syntax error at or near "user"
In pgadmin:
ERROR: syntax error at or near "user"
LINE 1: CREATE TABLE user (
********** Error **********
ERROR: syntax error at or near "user"
SQL state: 42601
Character: 14
This has nothing to do with the default schema. user is a reserved word.
You need to use double quotes to be able to create such a table:
CREATE TABLE "user" (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
email TEXT NOT NULL,
creation_date TIMESTAMP NOT NULL
);
But I strongly recommend not doing that. Find a different name that does not require a quoted identifier.

HibernateException: Missing table error for a Join Table using Grails 2.0.2 on MS SQL legacy database

I am trying to get a many-to-many relationship working using Grails 2.0.1 on Windows 7. I have exhausted both Google, this site, and my Grails books. Nothing worked. I am connecting to a MS SQL Server 2005 database that I have READ only privileges on and yes - it is a legacy database. Everything in the 2 individual tables works fine (views OK & all) but when I try to add the join table code I get an error:
org.hibernate.HibernateException: Missing table: dbo.IN_USR_DRAWING_PRIV
The table does indeed exist and I can see it fine using IntelliJ's IDEA 10.5 Data Sources view & the MS SQL Server Management Studio. The relevant part of the error is this (I can send more ... much more if needed) :
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManagerPostProcessor': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager': Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory': Invocation of init method failed; nested exception is org.hibernate.HibernateException: Missing table: dbo.IN_USR_DRAWING_PRIV
Here are the 2 domain classes :
class Drawing {
static hasMany = [appusers:Appuser]
String id
String drawingId //this is in the join table
String drawingName
static transients = ['name']
void setName(String name) {
id = name
}
String getName() {
return id
}
static mapping = {
table name: "IN_DRAWING", schema: "dbo"
version false
id column: 'DRAWING_ID', generator:'identity', insertable:false, updateable:false
drawingId column: "`DRAWING_ID`",insertable:false, updateable:false //this is in the join table
drawingName column: "`DRAWING_NAME`"
appusers column: '`USR_ID`',
joinTable: 'IN_USR_DRAWING_PRIV'
}
}
class Appuser {
static belongsTo = Drawing
static hasMany = [drawings:Drawing]
String id
String usrId //this is in the join table
String usrName
static transients = ['name']
void setName(String name) {
id = name
}
String getName() {
return id
}
static mapping = {
table name: 'IN_USR', schema: "dbo"
version false
id column:'USR_ID', generator:'identity', insertable:false, updateable:false //this is in the join table
drawings column: 'DRAWING_ID',
joinTable: 'IN_USR_DRAWING_PRIV'
usrName column: "`USR_NAME`"
}
}
And here is the schema for the join table:
dbo.IN_USR_DRAWER_PRIV
USR_ID (PK, varchar(23), not null)
DRAWING_ID (PK, FK, varchar(23), not null)
PRIV_ID (PK, int, not null)
GRAG reports it has a composite key of all 3 columns, which it does along with a FK on DRAWING_ID.
Solutions that I have tried :
This code (which fails with the "Missing Table" exception.
Adding a domain controller for the join table - same result.
Any hints/clues/solutions appreciated.
I fixed this by using Groovy SQL directly and passing in the T-SQL.

Resources