Given the following example for an Entity-Definition, there is a foreign key defined. As a developer and database engineer i would expect that the command dal:create:schema would also create the expected foreign keys. But this is not the case.
return new FieldCollection([
(new IdField('id', 'id'))->addFlags(new PrimaryKey(), new Required()),
(new LongTextField('comment', 'name'))->addFlags(new Required()),
(new FkField('order_id', 'orderId', OrderDefinition::class))->addFlags(new Required()),
new OneToOneAssociationField('order', 'order_id', 'id', OrderDefinition::class, false),
new CreatedAtField(),
new UpdatedAtField()
]);
Instead this is the result:
CREATE TABLE `order_refund` (
`id` BINARY(16) NOT NULL,
`comment` LONGTEXT NOT NULL,
`order_id` BINARY(16) NOT NULL,
`created_at` DATETIME(3) NOT NULL,
`updated_at` DATETIME(3) NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
However, it seems like that ManyToOneAssociations will add foreign keys. Is there something missing in the entity definition?
The command you mentioned is using the SchemaGenerator which has a method to generate Foreign keys:
\Shopware\Core\Framework\DataAbstractionLayer\SchemaGenerator::generateForeignKeys
Looking at this method it seems to work only fields of the type ManyToOneAssociationField
private function generateForeignKeys(EntityDefinition $definition): string
{
$fields = $definition->getFields()->filter(
function (Field $field) {
if (!$field instanceof ManyToOneAssociationField) {
return false;
}
return true;
}
);
I also think it is a shortcoming of this function that it does not generate foreign keys for fields of the type OneToOneAssociationField. Maybe you can try to adjust this filtering and see if it works and make a pull request on GitHub for the benefit of yourself and other developers?
I am using SQLite with ionic
Ionic:
Ionic CLI : 6.6.0 (C:\Users\ADEEL\AppData\Roaming\npm\node_modules\#ionic\cli)
Ionic Framework : #ionic/angular 5.0.5
#angular-devkit/build-angular : 0.900.7
#angular-devkit/schematics : 9.0.7
#angular/cli : 9.0.7
#ionic/angular-toolkit : 2.2.0
Cordova:
Cordova CLI : 9.0.0 (cordova-lib#9.0.1)
Cordova Platforms : android 8.1.0, browser 6.0.0
Cordova Plugins : cordova-plugin-ionic-webview 4.1.3, (and 9 other plugins)
Utility:
cordova-res (update available: 0.13.0) : 0.6.0
native-run (update available: 1.0.0) : 0.2.8
System:
Android SDK Tools : 26.1.1 (C:\Users\ADEEL\AppData\Local\Android\Sdk)
NodeJS : v12.16.1 (C:\Program Files\nodejs\node.exe)
npm : 6.13.4
OS : Windows 10
I have a table with 16 records in log_book table and 1 record each in department and location. when i run the query first time it will take almost 15 to 20 seconds but after that it runs in milliseconds. Calling function as follow
getLogBooks(): Promise<LogBook[]>{
return this.storage.executeSql(`SELECT l.id, l.log_book_id, IFNULL(l.machine_no, "") machine_no , d.department_name, loc.location_name, l.section, l.area
FROM log_book l
INNER JOIN departments d ON l.department_id = d.id
INNER JOIN locations loc ON l.location_id = loc.id
WHERE l.deleted_at IS NULL`, [])
.then(res => {
const items: LogBook[] = [];
console.log('Log BOOK', res.rows.length)
if (res.rows.length > 0) {
for (let i = 0; i < res.rows.length; i++) {
items.push({
id: res.rows.item(i).id,
LogBookID: res.rows.item(i).log_book_id,
MachineNo: res.rows.item(i).machine_no,
Department: res.rows.item(i).department_name,
Location: res.rows.item(i).location_name,
Section: res.rows.item(i).section,
Area: res.rows.item(i).area
});
}
}
return items;
});
}
Table structure
CREATE TABLE IF NOT EXISTS `log_book` (
`id` integer primary key autoincrement,
`log_book_id` varchar(50) NOT NULL,
`machine_no` varchar(50) DEFAULT NULL,
`department_id` int(11) NOT NULL,
`location_id` int(11) NOT NULL,
`section` varchar(50) NOT NULL,
`area` varchar(50) NOT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`created_by` int(11) DEFAULT NULL,
`updated_by` int(11) DEFAULT NULL,
`deleted_at` datetime DEFAULT NULL
);
CREATE TABLE IF NOT EXISTS `departments` (
`id` integer primary key autoincrement,
`department_name` varchar(50) NOT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`created_by` int(11) DEFAULT NULL,
`updated_by` int(11) DEFAULT NULL,
`deleted_at` datetime DEFAULT NULL
);
CREATE TABLE IF NOT EXISTS `locations` (
`id` integer primary key autoincrement,
`location_name` varchar(50) NOT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`created_by` int(11) DEFAULT NULL,
`updated_by` int(11) DEFAULT NULL,
`deleted_at` datetime DEFAULT NULL
);
What i am doing wrong.
Thanking you in anticipation
A customer needs a trigger for his new management tool. It works so far, but now he wants to get values from another table.
What does it mean? Take a short look at the (working) trigger:
CREATE OR REPLACE TRIGGER reldb_export_T_Import3_In
AFTER UPDATE OR INSERT OR DELETE ON infor.RELDB
FOR EACH ROW
DECLARE KST varchar(1000 BYTE);
BEGIN
IF (:new.ZUST = 4 AND :old.ZUST = 3 AND :old.SAINT = 60)
THEN
INSERT INTO infor2infoboard.T_Import3_In
(Idx, Timestamp, ObjectId, Text, RowUid, GroupName, GroupIndex, PredTimeCondition, PredGapValue, Service, ReqQuan, ReqDur,
Efficiency, BackColor, HighlightColor, Brightness, CellOffsetY, Fixed, Font, FontColor, Height, EarliestStart, LastDeliveryDate, RoleId,
StatusIds, WithReservation, LastChange, LastEditedBy, Opacity, IsProcess, CheckSymbol, Link, Priority, IconPath, Adress, CA1, CA2,
CA3, CA4, CA5, CA6, CA7, CA8, CA9, CA10, CA11, CA12, CA13, CA14, CA15,
CA16, CA17, CA18, CA19, CA20, CA21, CA22, CA23, CA24, CA25,
CA26, CA27, CA28, CA29, CA30, CA31, CA32)
VALUES
(seq_t_import3_in.nextval, sysdate, :old.RNR, NULL, CASE WHEN :NEW.KST = '3710' THEN 'Pool TB-M 1;Pool TB-M 2;Pool TB-M 3;Pool TB-M 4;Pool TB-M 5' ELSE KST END, :old.Komm, NULL, NULL, NULL, :old.KTXT, :old.TA_4, NULL,
NULL, CASE WHEN :new.MNR = '3740' THEN 'GREEN' WHEN :new.MNR != '3740' THEN 'BLUE' END, NULL, NULL, NULL, NULL, NULL, NULL, NULL, :old.TERM_2, :old.TERM_1, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, SUBSTR(:old.ANR, 1, 10), :old.KOMM, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL);
END IF;......
Now he want to replace one of the last NULLS with a selected value.
The statement should look like this:
SELECT KTXT FROM RELDB WHERE ANR = :old.ANR and SAEXT = 'H';
So, for example:
NULL, (SELECT KTXT FROM RELDB WHERE ANR = :old.ANR and SAEXT = 'H';), SUBSTR(:old.ANR, 1, 10), :old.KOMM, NULL
My problem: I'm getting an error, that the trigger couldn't notice some changes. The trigger won't get fired.
So does anyone know how I can use or how I can get selected values (from the same (!!!) table which the trigger is listening to?
I'd appreciate your help :)
Cheers,
Dom
In Oracle, you cannot select from the same table you are changing, this is the mutating table error. See https://asktom.oracle.com/pls/apex/f?p=100:11:0::::p11_question_id:9579487119866
I wrote the following code and I'm trying to make an install to create the databases and tables for the SQL but I can't figure out why it's not creating the databases or the tables.
CONFIG.PHP
<?php
// Database Details
$host = 'localhost';
$user = 'root';
$password = '';
//Install Settings
$root_username = 'root';
$root_password = 'password';
// Install Settings Advanced - Do Not Modify For Default Settings
$database = 'Sims2';
?>
INSTALL.PHP
<?php
include 'config.php';
// Remove any instance of .mysqli_connect_error() before publishing
$conn = mysqli_connect($host,$user,$password);
if (!$conn) {die("Connection failed: ".mysqli_connect_error());};
$sql = "CREATE DATABASE Sims2";
if (!$conn){die("Error creating database: ".mysqli_connect_error());};
$sql = "CREATE TABLE TEACHERS (
id INT(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
uid VARCHAR(128) NOT NULL,
pwd VARCHAR(128) NOT NULL
);";
if(!$conn){die("Error creating table: ".mysqli_connect_error());};
$sql = "CREATE TABLE STUDENTS (
id INT(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
first VARCHAR(64) NOT NULL,
last VARCHAR(64) NOT NULL,
gender VARCHAR(6) NOT NULL,
dob VARCHAR(10) NOT NULL,
semail VARCHAR(64) NOT NULL,
address VARCHAR(120) NOT NULL,
phone VARCHAR(15) NOT NULL,
tutor VARCHAR(64) NOT NULL
);";
if(!$conn){die("Error creating table: ".mysqli_connect_error());};
$sql = "INSERT INTO TEACHERS (uid, pwd) VALUES ($root_username,$root_password)";
if(!$conn){die("Error creating root account: ".mysqli_connect_error());};
echo "Done";
?>
Any help would be appreciated
I want to make the auth_user.email case-insensitive unique, nullable and default null. The following almost works:
from django.db.models.signals import post_syncdb
import app.models
SQLITE_AUTH_REFORM = [
"PRAGMA writable_schema = 1;",
"""UPDATE SQLITE_MASTER SET SQL =
'CREATE TABLE auth_user (
"id" integer NOT NULL PRIMARY KEY,
"username" varchar(30) NOT NULL UNIQUE,
"first_name" varchar(30) NOT NULL,
"last_name" varchar(30) NOT NULL,
"email" varchar(75) DEFAULT NULL,
"password" varchar(128) NOT NULL,
"is_staff" bool NOT NULL,
"is_active" bool NOT NULL,
"is_superuser" bool NOT NULL,
"last_login" datetime NOT NULL,
"date_joined" datetime NOT NULL
)' WHERE NAME = 'auth_user';""",
"PRAGMA writable_schema = 0;",
]
def post_syncdb_callback(sender, **kwargs):
from django.db import connections
from django.conf import settings
cursor = connections['default'].cursor()
if 'sqlite' in settings.DATABASES['default']['ENGINE']:
for stmt in SQLITE_AUTH_REFORM:
cursor.execute(stmt)
cursor.execute(
"CREATE UNIQUE INDEX IF NOT EXISTS auth_user_email_unique "
"ON auth_user (email COLLATE NOCASE);"
)
else: # Oracle
cursor.execute(
"CREATE UNIQUE INDEX auth_user_email_unique "
"ON auth_user (upper(email));"
)
cursor.cursor.close()
post_syncdb.connect(post_syncdb_callback, sender=app.models)
I can
User.objects.create(username=str(random.random()), email=None)
To my heart's content. And also,
User.objects.create(username=str(random.random()), email='Foo')
User.objects.create(username=str(random.random()), email='foo')
...
IntegrityError: column email is not unique
The only problems is that the DEFAULT NULL does not seem to work: User.objects.create(username=str(random.random())) creates a user with an empty-string email.
However, in a unit-test, I believe something is going on that prevents the post-syncdb hook from working:
class DjangoUserTest(TestCase):
def test_unique_nullable_email(self):
import IPython; IPython.embed()
u1 = User.objects.create(username="u1", email=None)
u2 = User.objects.create(username="u2", email=None)
I can drop into the ipython shell and see that the table has been apparently modified:
In [1]: from django.db import connection
In [2]: c = connection.cursor()
In [3]: r = c.execute("select `sql` from sqlite_master WHERE tbl_name = 'auth_user';")
In [4]: r.fetchall()
Out[4]:
[(u'CREATE TABLE auth_user (\n "id" integer NOT NULL PRIMARY KEY,\n "username" varchar(30) NOT NULL UNIQUE,\n "first_name" varchar(30) NOT NULL,\n "last_name" varchar(30) NOT NULL,\n "email" varchar(75) DEFAULT NULL,\n "password" varchar(128) NOT NULL,\n "is_staff" bool NOT NULL,\n "is_active" bool NOT NULL,\n "is_superuser" bool NOT NULL,\n "last_login" datetime NOT NULL,\n "date_joined" datetime NOT NULL\n)',),
(None,),
(u'CREATE UNIQUE INDEX auth_user_email_unique ON auth_user (email COLLATE NOCASE)',)]
However, upon trying to do the creates, I get, IntegrityError: auth_user.email may not be NULL. How did this happen when the select sql from sqlite_master WHERE tbl_name = 'auth_user'; clearly says "email" varchar(75) DEFAULT NULL. I feel like I just need to commit the post_syncdb stuff or sth. Any ideas?
UPDATE: No amount of connection.commit(), cursor.close() helps, using TransactionTestCase does not help.