Create table using Go-Gorp fails to set column details - mysql

Trying to create the table using Gorp-Go ORM package. Was able to successfully create the table in MySql but failed to attach column details.
type Data struct {
id int `db:"pid"`
name string `db:",size:50"`
}
Gorp hook
Dbm.AddTableWithName(Data{}, "data_test").SetKeys(true, "id")
Dbm.CreateTablesIfNotExists()
Dbm is pointer to gorp.DbMap. The resultant table has pid and ,size:50 has name. Have tried with
type Data struct {
id int `db:"pid"`
name string `db:"name:xyz,size:50"`
}
Still the resultant column name is "name:xyz,size:50"

According to this comment, the size feature is still available in only dev branch.
You can achieve this by explicitly setting maxsize though. Example:
dt := Dbm.AddTableWithName(Data{}, "data_test").SetKeys(true, "id")
dt.ColMap("xyz").SetMaxSize(50)
Dbm.CreateTablesIfNotExists()
....

I believe the column name doesn't require "name"
Try db:"xyz,size:50"

Related

How to pass dynamic table name in gorm model

I am using Gorm ORM for my current application. I have one model correspondents to many tables with identical table structures(i.e. column name and type). So my requirement how can I change the table name dynamically while doing the query.
For e.g.
I have product model like Product.go
type Product struct{
ID int
Name strig
Quantity int
}
And we have different products like shirts, jeans and so on and we have same tables like shirts, jeans.
Now I wanted to query the product as per name of the product how can we do that also want to have table created through migrations. But there is only One model than how can we run use Automigrate feature with Gorm.
Updated for GORM v2
DEPRECATED: TableName will not allow dynamic table name anymore, its result will be cached for future uses.
There is a much easier way to create several tables using the same struct:
// Create table `shirts` & `jeans` with the same fields as in struct Product
db.Table("shirts").AutoMigrate(&Product{})
db.Table("jeans").AutoMigrate(&Product{})
// Query data from those tables
var shirts []Product
var jeans []Product
db.Table("shirts").Find(&shirts)
db.Table("jeans").Where("quantity > 0").Find(&shirts)
But, now on the second thought, I would suggest using the embedded struct so that you won't have to call Table in every query and you can also have additional fields per model while still sharing the same table structure.
type ProductBase struct {
ID int
Name strig
Quantity int
}
type Shirt struct {
ProductBase
NeckType string
}
type Jean struct {
ProductBase
Ripped bool
}
db.AutoMigrate(&Shirt{}, &Jean{})
shirt, jeans := Shirt{}, make([]Jean, 0)
db.Where("neck_type = ?", "Mandarin Collar").Last(&shirt)
db.Where("ripped").Find(&jeans)
Old answer for GORM v1
You're almost there by using table field inside the struct:
type Product struct{
ID int
Name strig
Quantity int
// private field, ignored from gorm
table string `gorm:"-"`
}
func (p Product) TableName() string {
// double check here, make sure the table does exist!!
if p.table != "" {
return p.table
}
return "products" // default table name
}
// for the AutoMigrate
db.AutoMigrate(&Product{table: "jeans"}, &Product{table: "skirts"}, &Product{})
// to do the query
prod := Product{table: "jeans"}
db.Where("quantity > 0").First(&prod)
Unfortunately, that does not work with db.Find() when you need to query for multiple records... The workaround is to specify your table before doing the query
prods := []*Product{}
db.Table("jeans").Where("quantity > 0").Find(&prods)

SQLGrammar error when querying MySql view

When a run a GET request i get an exception o.h.engine.jdbc.spi.SqlExceptionHelper : Unknown column 'disburseme0_.reason_type' in 'field list' in stack trace even though i have configured the field correctly in the entity class. I have a Spring Boot SOAP interface that is querying a MySql database view. I have assigned one of the unique keys from the parent tables as the view Id in JPA.
Part of my entity class has:
#Entity
#Table(name="disbursement_payload")
public class Disbursement {
#Id
#Column(name="ID")
private long disbursementId;
#Column(name="ReasonType")
private String reasonType;
public long getDisbursementId() {
return disbursementId;
}
public void setDisbursementId(long disbursementId) {
this.disbursementId = disbursementId;
public String getReasonType() {
return reasonType;
}
public void setReasonType(String reasonType) {
this.reasonType = reasonType;
}
I have the view as:
CREATE VIEW disbursement_payload AS (
SELECT
iso_number AS Currency,
trans_desc AS ReasonType,
account_number AS ReceiverParty,
amount AS Amount
FROM m_payment_detail, m_loan_transaction
WHERE m_payment_detail.`id`= m_loan_transaction.`payment_detail_id` AND
m_payment_detail.`payment_type_id`=2
);
Is there something im missing , in the entity or view definition? I have read one of the comments here could not extract ResultSet in hibernate that i might have to explicitly define the parent schemas. Any assistance, greatly appreciated.
do the mapping for db column and class var name based on camelCase conversion basded on underscore _ separated name
you could try using
CREATE VIEW disbursement_payload AS (
SELECT iso_number AS currency
, trans_desc AS reason_type
, account_number AS receiver_rarty
, amount AS amount
FROM m_payment_detail
INNER JOIN m_loan_transaction
ON m_payment_detail.`id`= m_loan_transaction.`payment_detail_id`
AND m_payment_detail.`payment_type_id`=2
);
the view code is SQL code and hibernate see a view as a table, so the conversion of column name is base on the same rules
and a suggestion you should not use (older) implicit join based on where condition you should use (more recent) explici join sintax ..

MySQL to MSSQL keep foreign key relationships

I am currently trying to migrate from an old MySQL (5.0) to MSSQL. Because I must keep the primary key relationships, I am now facing a problem. Some data inside a table begin with the id of 6102 instead of one. I can solve this by increasing the seed, which works. Now, after several thousand of data sets, I have some leaps e.g. from id 22569 to 22597. This occurres multiple times.
What I basically do at the moment is, select all data from the source db (MySQL), map them into a generated model und try to map this model to my target model (MSSQL). (I do this because the target, new structure differs a little from the existing one.) When I ignore those leaps, I am getting later on several other tables a foreign key violation.
So my solution currently would be, to count from the beginning each mapping and when the id of the current model differs from the counter, to reset manually the seed in the database.
DBCC CHECKIDENT (mytable, RESEED, idFromCurrentModel);
Is there a possibility to force entity framework, respectively SQL Server to accept the id from my model instead of ignoring it and use the ident value?
Thanks for reading and best regards
EDIT
Just if anybody is wondering how I solved this, here it is:
var context = new TestEntities();
// map mysql data to mssql model and convert data
// let's assume I did this
var mapped = new List<Test>()
{
new Test() {id= 42, bar = "foo", created = DateTime.Now},
new Test() {id= 1337, bar = "bar", created = DateTime.Now}
};
var transaction = context.Database.BeginTransaction();
context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT [SeedingTest].[dbo].[Test] ON");
context.Test.AddRange(mapped);
context.SaveChanges();
context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT [SeedingTest].[dbo].[Test] OFF");
transaction.Commit();
context.Dispose();
This only works when I do this:
Right click on my *.edmx file, open, and remove the
StoreGeneratedPattern="Identity"
in your identity column. In my case this looked like this:
...
<Property Name="id" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />
...
After removing this, EF was no longer ignoring my set id's.
Source
Additional information:
Adding this attribute
[DatabaseGenerated(DatabaseGeneratedOption.None)]
to my id in my generated model, did not work.
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int foo { get; set; }
public string bar { get; set; }
...
The easiest way is to set the seed initially to the current max Id value + 1. Then, when inserting the converted rows do the following
set identity_insert on tablename -- stops generation of IDENTITY, requires user to supply it
insert into tablename values (Id....) -- supply value of Id
set identity_insert_off tablename -- turn inedtity generation back on
This does it quite nicely.

How can I make Fanbatis #Column annotation to map Fantom class attribute to DB column correctly?

I'm using Fanbatis framework to access a MySQL database. The documentation here: http://www.talesframework.org/fanbatis/ says that I can use the #Column annotation to map a class attribute to a column with a different name:
#Column{name="xx"} - By default column name is assumed to be the field name,
to change this use this annotation on a field
I have this class...
using fanbatis
#Table {name = "APPS"}
class App
{
#Primary
Str? id
Str? name
#Column{name="description"}
Str? descr
}
And the APPS table created with this SQL:
create table APPS (
ID varchar(36) not null,
NAME varchar(100) not null,
DESCRIPTION varchar(400) ,
primary key (ID)
);
And I'm trying to retrieve a record from the database using this DAO
class AppDao
{
static App? findById(Str id)
{
S<|
select * from apps where id = #{id}
|>
}
}
My code compiles fine, but when I run it, passing in the ID of an existing record, it retrieves the record from the database and set the values of the attributes that match the column names, but the app.descr remains null. However, if I just remove the #Column annotation from the "descr" attribute and rename it to match the column ("description"), then the code runs fine and returns the expected values.
-- Run: auth::TestAppDao.testFindById...
Test setup!
app.id: 0615a6cb-7bda-cc40-a274-00130281bd51
app.name: MyApp
app.descr: null
TEST FAILED
sys::TestErr: Test failed: null != "MyApp descr" [sys::Str]
fan.sys.Test.err (Test.java:206)
fan.sys.Test.fail (Test.java:198)
fan.sys.Test.verifyEq (Test.java:121)
fan.sys.Test.verifyEq (Test.java:90)
auth::TestAppDao.testFindById (TestAppDao.fan:36)
java.lang.reflect.Method.invoke (Unknown)
fan.sys.Method.invoke (Method.java:559)
fan.sys.Method$MethodFunc.callList (Method.java:204)
fan.sys.Method.callList (Method.java:138)
fanx.tools.Fant.runTest (Fant.java:191)
fanx.tools.Fant.test (Fant.java:110)
fanx.tools.Fant.test (Fant.java:32)
fanx.tools.Fant.run (Fant.java:284)
fanx.tools.Fant.main (Fant.java:327)
Test teardown!
Am I doing something wrong or is this a bug in Fanbatis?
It could be due to case sensitivity - see MySQL 9.2.2. Identifier Case Sensitivity
Although database and table names are not case sensitive on some
platforms, you should not refer to a given database or table using
different cases within the same statement. The following statement
would not work because it refers to a table both as my_table and as
MY_TABLE:
mysql> SELECT * FROM my_table WHERE MY_TABLE.col=1;
Try:
#Column{name="DESCRIPTION"}
It's also mentioned in this question.

How to get the auto-increment primary key value in MySQL using Hibernate

I'm using Hibernate to access MySQL, and I have a table with an auto-increment primary key.
Everytime I insert a row into the table I don't need to specify the primary key. But after I insert a new row, how can I get the relative primary key immediately using hibernate?
Or I can just use jdbc to do this?
When you save the hibernate entity, the id property will be populated for you. So if you have
MyThing thing = new MyThing();
...
// save the transient instance.
dao.save(thing);
// after the session flushes, thing.getId() should return the id.
I actually almost always do an assertNotNull on the id of a persisted entity in my tests to make sure the save worked.
Once you're persisted the object, you should be able to call getId() or whatever your #ID column is, so you could return that from your method. You could also invalidate the Hibernate first level cache and fetch it again.
However, for portability, you might want to look at using Hibernate with sequence style ID generation. This will ease the transition away from MySQL if you ever need to. Certainly, if you use this style of generator, you'll be able to get the ID immediately, because Hibernate needs to resolve the column value before it persists the object:
#Id
#GeneratedValue (generator="MY_SEQ")
#GenericGenerator( name = "MY_SEQ",
strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
parameters = {
#Parameter(name = "sequence_name", value = "MY_SEQ"),
#Parameter(name = "initial_value", value = "1"),
#Parameter(name = "increment_size", value = "10") }
)
#Column ( name = "id", nullable = false )
public Long getId () {
return this.id;
}
It's a bit more complex, but it's the kind of thing you can cut and paste, apart from changing the SEQUENCE name.
When you are calling a save() method in Hibernate, the object doesn't get written to the database immediately. It occurs either when you try to read from the database (from the same table?) or explicitly call flush(). Until the corresponding record is not inserted into the database table, MySQL would not allocate an id for it.
So, the id is available, but not before Hibernate actually inserts the record into the MySQL table.
If you want, you can get the next primary key independently of an object using:
Session session = SessionFactoryUtil.getSessionFactory().getCurrentSession();
Query query = session.createSQLQuery( "select nextval('schemaName.keySequence')" );
Long key = (Long) query.list().get( 0 );
return key;
Well in case of auto increment generator class, when we use the save() method it returns the primary key (assuming its id). So it returns that particular id, so you can do this
int id = session.save(modelClass);
And return id