Unable to specify the name of an index for a secondary table with DataNucleus - jdo

I've got the following JDO class that I'm trying to use with DataNucleus 4.1.0-release:
#PersistenceCapable(table = "accounts", identityType = IdentityType.APPLICATION, detachable = "true")
public final class Account {
#Persistent(primaryKey = "true", valueStrategy = IdGeneratorStrategy.IDENTITY)
#Column(allowsNull = "false")
private long id;
// A Set of enum constants.
#Persistent(table = "account_roles")
#Join(column = "account_id", primaryKey = "account_roles_account_id_role_pkey", foreignKey = "account_roles_account_id_fkey", index = "account_roles_account_id_idx")
#Element(column = "role")
private Set<SecurityRole> roles;
}
Running schema generation for this table against PostgreSQL gives me the following, though:
-- Table "accounts" for classes [com.trickle.api.accounts.Account]
CREATE TABLE "accounts"
(
"id" SERIAL,
CONSTRAINT "accounts_PK" PRIMARY KEY ("id")
);
-- Table "account_roles" for join relationship
CREATE TABLE "account_roles"
(
"account_id" int8 NOT NULL,
"role" varchar(255) NOT NULL,
CONSTRAINT "account_roles_account_id_role_pkey" PRIMARY KEY ("account_id","role")
);
-- Constraints for table "accounts" for class(es) [com.trickle.api.accounts.Account]
-- Constraints for table "account_roles"
ALTER TABLE "account_roles" ADD CONSTRAINT "account_roles_account_id_fkey" FOREIGN KEY ("account_id") REFERENCES "accounts" ("id") INITIALLY DEFERRED ;
CREATE INDEX "account_roles_N49" ON "account_roles" ("account_id");
Note the index name of "account_roles_N49", instead of the "account_roles_account_id_idx" that I'd specified in the class' annotation. What am I doing wrong here?

Related

Why is this Knex migration not forcing a column to be unique?

I'm creating a SQLite database with this Knex migration. When I review the DB in SQLiteStudio, it doesn't indicate that the email column is unique. Is there a mistake I'm missing?
exports.up = function (knex) {
return knex.schema
.createTable('users', users => {
users.increments();
users.string('email', 128).unique().notNullable();
users.string('password', 256).notNullable();
})
Generated DDL code:
CREATE TABLE users (
id INTEGER NOT NULL
PRIMARY KEY AUTOINCREMENT,
email VARCHAR (128) NOT NULL,
password VARCHAR (256) NOT NULL
);
Alternatives I've tried that didn't work:
-Switching order of unique() and notNullable()
users.string('email', 128).notNullable().unique()
-Creating a separate line to add the Unique constraint
.createTable('users', users => {
users.increments();
users.string('email', 128).notNullable();
users.string('password', 256).notNullable();
users.unique('email');
})
It's unique, you're just not going to see it in the CREATE TABLE statement. SQLite sets a UNIQUE constraint by creating an index with the UNIQUE qualifier. Take the following Knex migration, for example:
exports.up = knex =>
knex.schema.debug().createTable("users", t => {
t.increments("id");
t.string("name").unique();
});
Note debug(), very handy if you want to see what SQL is being generated. Here's the debug output:
[
{
sql: 'create table `users` (`id` integer not null ' +
'primary key autoincrement, `name` ' +
'varchar(255))',
bindings: []
},
{
sql: 'create unique index `users_name_unique` on `users` (`name`)',
bindings: []
}
]
As you can see, a second statement is issued to create the UNIQUE constraint. If we now go and look at the database, we'll see something like:
07:48 $ sqlite3 dev.sqlite3
sqlite> .dump users
BEGIN TRANSACTION;
CREATE TABLE `users` (`id` integer not null primary key autoincrement,
`name` varchar(255));
CREATE UNIQUE INDEX `users_name_unique` on `users` (`name`);
COMMIT;
As an aside, you may wish to do more research about the possible length of user emails. See this answer as a starting point.

sqlite JDBC metadata.getPrimaryKeys return info of foreign keys

sqlite JDBC metadata.getPrimaryKeys return info of foreign keys. e.g.,
create table Foo (id integer, bar_id integer,
primary key(id),
foreign key (bar_id) references Bar(id))
JDBC:
DatabaseMetaData databaseMetaData = connection.getMetaData();
ResultSet rs = databaseMetaData.getPrimaryKeys("c:/test_db", null, "Foo");
rs.next();
String columnName = rs.getString("COLUMN_NAME");
assertEquals("id", columnName);
Each primary key column description has the following columns:
TABLE_CAT String => table catalog (may be null)
TABLE_SCHEM String => table schema (may be null)
TABLE_NAME String => table name
COLUMN_NAME String => column name
KEY_SEQ short => sequence number within primary key( a value of 1 represents the first column of the primary key, a value of 2 would represent the second column within the primary key).
PK_NAME String => primary key name (may be null)
org.junit.ComparisonFailure: expected:<[]id> but was:<[foreign key (bar_]id>

peewee migration "has no column named FOREIGN"

I'm trying to use peewee's migration module to rename a column from name to title in my page table. However I'm running this confusing error:
peewee.OperationalError: table page__tmp__ has no column named FOREIGN
My guess is that it has something to do with the need to create an intermediary table when using sqlite.
Current Model:
Full source is here https://github.com/csytan/textmug/blob/master/db.py
class User(BaseModel):
id = peewee.CharField(primary_key=True, max_length=20)
class Page(BaseModel):
id = peewee.PrimaryKeyField()
name = peewee.TextField(unique=True, null=True)
user = peewee.ForeignKeyField(User, null=True, related_name='pages')
Migration Script:
from playhouse import migrate
my_db = migrate.SqliteDatabase('database')
migrator = migrate.SqliteMigrator(my_db)
with my_db.transaction():
migrate.migrate(
migrator.rename_column('page', 'name', 'title')
)
I ended up doing it manually with the sqlite3 command line tool:
BEGIN;
ALTER TABLE "page" RENAME TO "page_tmp";
CREATE TABLE "page" ("id" INTEGER NOT NULL PRIMARY KEY, "title" TEXT, "user_id" TEXT, "created" DATETIME NOT NULL, "text" TEXT NOT NULL, "public" SMALLINT NOT NULL, "encrypted" SMALLINT NOT NULL, FOREIGN KEY ("user_id") REFERENCES "user" ("id"));
INSERT INTO "page" SELECT "id","name","user_id","created","text","public","encrypted" FROM "page_tmp";
DROP TABLE "page_tmp";
COMMIT;

Simple.Data Sqlite Insert returns Null

Im using Simple.Data to insert data into an Sqlite database. I read on the wiki that Insert returns the inserted data. I need to get the latest rowID (identity). But I get Null instead.
Using the Stable version from NuGet.
var db = Database.OpenFile("Database.db");
var x = db.Scan.Insert(Name:"Test", Description:"test", CreationDate:DateTime.Now, DocumentDate:DateTime.Now, ModifiedDate:DateTime.Now);
DB schema:
CREATE TABLE Scan (
ID INTEGER PRIMARY KEY,
Name NVARCHAR( 50 ) NOT NULL,
Description TEXT,
CreationDate DATETIME NOT NULL,
DocumentDate DATETIME NOT NULL,
ModifiedDate DATETIME NOT NULL
);
Does this even work for SQLite? If not whats the best way to retrieve the rowID of the inserted record?
Had the same "issue".
The problem lies within your schema.
You have to add identity to your primary key column:
ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
Then you get back the row and you can i.e. create a new object with it:
var x = db.Scan.Insert(Name:"Test", Description:"test", CreationDate:DateTime.Now, DocumentDate:DateTime.Now, ModifiedDate:DateTime.Now);
return new Scan { ID = (int)x.ID, Name = x.Name, ... }
From the Wiki:
If you have an IDENTITY column defined on your table, then the Insert
methods will all return a copy of the record fetched from the
database, so all defaulted values are set. In 0.4, support for other
ways of fetching the inserted row will be added.

LINQPad create sqlite database in C# query

The IQ Connection plugin for LINQPad that allows one to use SQLite has a checkbox for "Create database if missing" but that will only create an empty file. Is there anyway to build the tables automatically when the file doesn't exist?
Shouldn't there be a way to get the DataContext and create tables using that interface? Hopefully causing LINQPad to update its DataContext at the same time.
The best I've been able to do so far is below, creating DbCommands and executing them on the first run after deleting the sqlite file, then I have to refresh the database, and run it again.
void Main()
{
if (!File.Exists(this.Connection.ConnectionString.Split('=')[1]))
{
"CREATING DATABASE TABLES".Dump();
CREATE_TABLES();
}
else
{
"RUNNING CODE".Dump();
//Code goes here...
}
}
public void CREATE_TABLES()
{
this.Connection.Open();
System.Data.Common.DbCommand sup = this.Connection.CreateCommand();
sup.CommandText = #"create table MainTable
(
MainTableID INTEGER not null PRIMARY KEY AUTOINCREMENT,
FileName nvarchar(500) not null
)";
sup.ExecuteNonQuery();
sup.CommandText = #"create table SubTable
(
SubTableID int not null,
MainTableID int not null,
Count int not null,
primary key (SubTableID, MainTableID),
FOREIGN KEY(MainTableID) REFERENCES MainTable(MainTableID)
)";
//Apparently this version of sqlite doesn't support foreign keys really
sup.ExecuteNonQuery();
this.Connection.Close();
}
Just set the query language dropdown to 'SQL', type in the DDL and hit F5. For instance:
PRAGMA foreign_keys = ON
GO
create table Customer
(
ID int not null primary key,
Name nvarchar(30) not null
)
GO
create table Purchase
(
ID int not null primary key,
CustomerID int null references Customer (ID),
Date datetime not null,
Description varchar(30) not null,
Price decimal not null
)
(Note the syntax for creating foreign key constraints.)
Once you're done, right-click the connection in the Schema Explorer and choose 'Refresh'. You can then switch the query language back to C# Expression or C# Statements and start querying in a proper query language :)

Resources