Entity Framework 'properties expression is not valid' when mapping table - entity-framework

Table definition:
CREATE TABLE [Index].[Dependency] (
[RevisionId] INT NOT NULL,
[MapCode] VARCHAR (10) NOT NULL,
[GroupId] SMALLINT NOT NULL,
[DependencyTypeId] TINYINT NOT NULL,
[InputThreshold] DECIMAL (9, 2) NOT NULL,
[InjectMapCode] VARCHAR (10) NULL,
[InjectAmount] DECIMAL (9, 2) NOT NULL,
CONSTRAINT [UQ_Dependency_RevisionId_MapCode_GroupId] UNIQUE NONCLUSTERED ([RevisionId] ASC, [MapCode] ASC, [GroupId] ASC),
CONSTRAINT [FK_Dependency_MapCode] FOREIGN KEY ([MapCode]) REFERENCES [Index].[Material] ([MapCode]),
CONSTRAINT [FK_Dependency_InjectMapCode] FOREIGN KEY ([InjectMapCode]) REFERENCES [Index].[Material] ([MapCode]),
CONSTRAINT [FK_Dependency_Revision] FOREIGN KEY ([RevisionId]) REFERENCES [Index].[DependencyRevision] ([DependencyRevisionId]),
CONSTRAINT [FK_Dependency_DependencyType] FOREIGN KEY ([DependencyTypeId]) REFERENCES [Index].[DependencyType] ([DependencyTypeId]),
CONSTRAINT [FK_Dependency_Group] FOREIGN KEY ([GroupId]) REFERENCES [Index].[Group] ([GroupId])
);
My attempt to map to it:
public class DependencyMap : EntityTypeConfiguration<Entities.Dependency>
{
public DependencyMap()
{
ToTable("Dependency", "Index");
HasKey(md => new { md.RevisionId, md.MapCode, md.GroupId });
Property(s => s.RevisionId).IsRequired().HasColumnName("RevisionId");
Property(s => s.MapCode).IsRequired().HasMaxLength(10).HasColumnName("MapCode");
Property(s => s.GroupId).IsRequired().HasColumnName("GroupId");
Property(s => s.DependencyTypeId).IsRequired().HasColumnName("DependencyId");
Property(s => s.InputThreshold).IsRequired().HasColumnName("InputThreshold").HasPrecision(9, 2);
Property(s => s.InjectMapCode).IsOptional().HasColumnName("InjectEngineMapCode").HasMaxLength(10);
Property(s => s.InjectAmount).HasColumnName("InjectAmount").IsRequired().HasPrecision(9, 2);
}
}
When I try to call a method that retrieves from the table an exception is thrown on
'HasKey(md => new { md.RevisionId, md.MapCode, md.GroupId })'
saying that 'properties expression is not valid. The expression should represent a property' when mapping the table. If anyone could show me how to properly map a table like this without explicitly defined primary key it would be much appreciated. Thanks.

Related

Make T4 reverse POCO generate classes properly

I am using a project which has T4MVC generating classes from a database table. I have several issues but this seems to be a pattern with them. I have not posted the .tt file because it is pretty large.
for example
HasRequired(a => a.AccountPaymentSettingId).WithMany(b => b.CustomerFileTypeAccountPaymentSettingFlexibles).HasForeignKey(c => c.AccountPaymentSettingId);
has a => a.AccountPaymentSettingId and I want a => a.AccountPaymentSetting
Here is the top of the .tt file to show the version
<## include file="..\\EF.Reverse.POCO.Core.ttinclude" #>
<#
// v2.17.1
It is not using desired names in the generated code.
This is what is generated:
public CustomerFileTypeAccountPaymentSettingFlexibleConfiguration(string schema)
{
ToTable(schema + ".Customer_FileType_Account_Payment_Setting_Flexible");
HasKey(x => x.AccountPaymentSettingFlexibleId);
Property(x => x.AccountPaymentSettingFlexibleId).HasColumnName("Account_Payment_Setting_Flexible_ID").IsRequired().HasColumnType("int").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(x => x.AccountPaymentSettingId).HasColumnName("Account_Payment_Setting_ID").IsRequired().HasColumnType("int");
Property(x => x.PaymentMethod).HasColumnName("Payment_Method").IsRequired().IsUnicode(false).HasColumnType("varchar").HasMaxLength(5);
Property(x => x.Priority).HasColumnName("Priority").IsRequired().HasColumnType("int");
Property(x => x.RowCreatedDate).HasColumnName("RowCreatedDate").IsRequired().HasColumnType("datetime2");
HasRequired(a => a.AccountPaymentSettingId).WithMany(b => b.CustomerFileTypeAccountPaymentSettingFlexibles).HasForeignKey(c => c.AccountPaymentSettingId);
HasRequired(a => a.PaymentMethod).WithMany(b => b.CustomerFileTypeAccountPaymentSettingFlexibles).HasForeignKey(c => c.PaymentMethod);
InitializePartial();
}
and this is my desired results:
public CustomerFileTypeAccountPaymentSettingFlexibleConfiguration(string schema)
{
ToTable(schema + ".Customer_FileType_Account_Payment_Setting_Flexible");
HasKey(x => x.AccountPaymentSettingFlexibleId);
Property(x => x.AccountPaymentSettingFlexibleId).HasColumnName("Account_Payment_Setting_Flexible_ID").IsRequired().HasColumnType("int").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(x => x.AccountPaymentSettingId).HasColumnName("Account_Payment_Setting_ID").IsRequired().HasColumnType("int");
Property(x => x.PaymentMethodCode).HasColumnName("Payment_Method").IsRequired().IsUnicode(false).HasColumnType("varchar").HasMaxLength(5);
Property(x => x.Priority).HasColumnName("Priority").IsRequired().HasColumnType("int");
HasRequired(a => a.AccountPaymentSetting).WithMany(b => b.CustomerFileTypeAccountPaymentSettingFlexibles).HasForeignKey(c => c.AccountPaymentSettingId);
HasRequired(a => a.PaymentMethod).WithMany(b => b.CustomerFileTypeAccountPaymentSettingFlexibles).HasForeignKey(c => c.PaymentMethodCode);
InitializePartial();
}
Just for completeness, this is the relevant part of the table (I left off some default and FK constraints to keep it compact)
CREATE TABLE [dbo].[Customer_FileType_Account_Payment_Setting_Flexible](
[Account_Payment_Setting_Flexible_ID] [int] IDENTITY(1,1) NOT NULL,
[Account_Payment_Setting_ID] [int] NOT NULL,
[Payment_Method] [varchar](5) NOT NULL,
[Priority] [int] NOT NULL,
[RowCreatedDate] [datetime2](7) NOT NULL,
CONSTRAINT [PK_Customer_FileType_Account_Payment_Setting_Flexible] PRIMARY KEY CLUSTERED
(
[Account_Payment_Setting_Flexible_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PayspanHealth_Data3],
CONSTRAINT [UK_CustomerFileTypeAccountPaymentSettingFlexible_SettingId_PaymentMethod] UNIQUE NONCLUSTERED
(
[Account_Payment_Setting_ID] ASC,
[Payment_Method] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PayspanHealth_Data3],
CONSTRAINT [UK_CustomerFileTypeAccountPaymentSettingFlexible_SettingId_Priority] UNIQUE NONCLUSTERED
(
[Account_Payment_Setting_ID] ASC,
[Priority] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PayspanHealth_Data3]
) ON [PayspanHealth_Data3]
GO
ALTER TABLE [dbo].[Customer_FileType_Account_Payment_Setting_Flexible] ADD CONSTRAINT [DF_CustomerFileTypeAccountPaymentSettingFlexible_RowCreatedDate] DEFAULT (sysdatetime()) FOR [RowCreatedDate]
GO
ALTER TABLE [dbo].[Customer_FileType_Account_Payment_Setting_Flexible] WITH CHECK ADD CONSTRAINT [FK_CustomerFileTypeAccountPaymentSettingFlexible_AccountPaymentSettingId] FOREIGN KEY([Account_Payment_Setting_ID])
REFERENCES [dbo].[Customer_FileType_Account_Payment_Settings] ([Account_Payment_Setting_ID])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[Customer_FileType_Account_Payment_Setting_Flexible] CHECK CONSTRAINT [FK_CustomerFileTypeAccountPaymentSettingFlexible_AccountPaymentSettingId]
GO
ALTER TABLE [dbo].[Customer_FileType_Account_Payment_Setting_Flexible] WITH CHECK ADD CONSTRAINT [FK_CustomerFileTypeAccountPaymentSettingFlexible_PaymentMethod] FOREIGN KEY([Payment_Method])
REFERENCES [dbo].[Payment_Method] ([Payment_Method_Code])
GO
ALTER TABLE [dbo].[Customer_FileType_Account_Payment_Setting_Flexible] CHECK CONSTRAINT [FK_CustomerFileTypeAccountPaymentSettingFlexible_PaymentMethod]
GO

Navigation Property Mapping on two different fields

I have a squirrely situation, where in some relationships a tables ID field is used as the key reference. But in other, older implementations, the Name field was used as the relationship mapping.
FileType:
ID | Name |....
FileTypeDetails:
ID | FileTypeId | ....
PostingGroupDetails :
FileType | ....
PostingGroupDetails.FileType has a map to FileType.Name. FileTypeDetails.FileTypeId maps to FileType.ID.
I am using the Fluent API structure to do the mappings manually but am running into a wall with this relationship mapping.
I though that doing a multi-key mapping might work but am unsure. Still in the design stage, and about to implement the interface side of the project.
Any ideas on how i make the mapping available to both, until we can consolidate the relationship mapping to one or the other?
EF Implementation:
FileType
I know FileType is currently Optional, but its only a direct correlation to the Table design. I am flagging it for schema updating, currently in practice it is a required field in order for the entry to be submitted.
ToTable( "FileType" , "Int" );
HasKey( ftd => ftd.ID );
Property( ftd => ftd.ID ).HasColumnName( "ID" )
.HasDatabaseGeneratedOption( DatabaseGeneratedOption.Identity );
Property( ftd => ftd.Name).HasColumnName( "Name" )
.IsOptional();
//Navigation Properties
HasMany( ftd => ftd.FileNames )
.WithRequired( fn => fn.FileType );
HasMany( ftd => ftd.PostingGroupDetails )
.WithRequired( pgd => pgd.FileTypeDetails );
FileNames
FileNames.FileTypeID relates to FileType.ID
ToTable( "FileNames" , "Int" );
HasKey( fn => fn.ID );
Property( fn => fn.ID ).HasColumnName( "ID" )
.HasDatabaseGeneratedOption( DatabaseGeneratedOption.Identity );
Property( fn => fn.FileTypeID ).HasColumnName( "FileTypeID" )
.IsRequired();
//Navigation Properties
HasRequired( fn => fn.FileType )
.WithMany( ftd => ftd.FileNames )
.HasForeignKey( fn => fn.FileTypeID );
PostingGroupDetails
PostingGroupDetails.FileType relates to FileType.Name
ToTable( "PostingGroupDetails " , "Int" );
HasKey( pgd => pgd.ID );
Property( pgd => pgd.ID ).HasColumnName( "ID" )
.HasDatabaseGeneratedOption( DatabaseGeneratedOption.Identity );
//Required Properties
Property( pgd => pgd.FileType ).HasColumnName( "FileType" )
.IsRequired();
//Navigation Properties
HasRequired( pgd => pgd.FileTypeDetails )
.WithMany( ftd => ftd.PostingGroupDetails );
Any ideas would be greatly appreciated. Refactoring the Database structure is not an option right now, but it is on the plate to be done.
Entity Framework allows for differences between the database model and the class model (or conceptual model). You can define primary keys in the conceptual model that don't exist, or aren't even constrained as unique, in the data model.
So you can (and have to) choose which fields you want to mark as PK in the conceptual model. You can only define associations to PKs that are defined in the conceptual model and there can only be one PK per entity. So for FileType you must either take ID or Name and then you can define an association with FileTypeDetails or PostingGroupDetails. For the other associations you know exist you'll have to write join queries. As in
from x in X
join y from Y on x.Name equals y.Name
select ...

How can I expose many-to-many tag-style relationship in a Catalyst app?

I'm building a database application in Catalyst, using jqGrid to do the messy work of handling the display of data. I've got almost everything working, except for being able to filter search results by "tags". I have three tables, with relationships like this:
package MyApp::Schema::Result::Project;
...
__PACKAGE__->has_many(
"job_flags",
"MyApp::Schema::Result::ProjectFlag",
{ "foreign.project_id" => "self.id" },
{ cascade_copy => 0, cascade_delete => 0 },
);
...
__PACKAGE__->many_to_many(flags => 'project_flags', 'flag');
1;
and
package MyApp::Schema::Result::Flag;
...
__PACKAGE__->has_many(
"project_flags",
"MyApp::Schema::Result::ProjectFlag",
{ "foreign.flag_id" => "self.id" },
{ cascade_copy => 0, cascade_delete => 0 },
);
...
__PACKAGE__->many_to_many(projects => 'project_flags', 'project');
1;
and finally, the join table
package MyApp::Schema::Result::ProjectFlag;
...
__PACKAGE__->belongs_to(
"flag",
"MyApp::Schema::Result::Flag",
{ id => "flag_id" },
{ is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
);
...
__PACKAGE__->belongs_to(
"project",
"MyApp::Schema::Result::Project",
{ id => "project_id" },
{ is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
);
...
1;
In my controller that provides the JSON data to jqGrid, I use Catalyst::TraitFor::Controller::jQuery::jqGrid::Search to translate the request parameters generated by jqGrid into DBIx::Class-style queries:
my $search_filter = $self->jqGrid_search($c->req->params);
my $project_rs = $c->model('DB::Project')->search(
$search_filter, {
join => 'project_flags',
group_by => 'id',
},
);
which is then passed on to the jqGrid page generator:
$project_rs = $self->jqgrid_page($c, $project_rs);
and then I iterate over the result set and build my jqGrid columns.
On the HTML side, I am able to build a JSON string like
{"groupOp":"AND","rules":[{"field":"project_flags.flag_id","op":"eq","data":"2"}]}
and, in this case, show Projects having a row in project_flags with flag id of 2.
I absolutely know I'm not doing this correctly! All of the documentation I can find on Catalyst and DBIx::Class demonstrates similar ideas, but I just can't understand how to apply them to this situation (not that I haven't tried).
How would I go about building "has_flag($flag_id)"-type accessors, and then be able to use them from within jqGrid's API? Where in my Catalyst app would this belong?
One of the ways I'd like to filter is by the lack of a particular flag also.
I've got to be honest with you, I'm not entirely sure I understand your question. It seems to be what you're asking has more to do with DBIx::Class than Catalyst--the latter I know very little about, the former I am learning more about every day. With that in mind, here's my best attempt at answering your question. I am using Mojolicious as the MVC, since that's what I know best.
First, I start by creating a many-to-many database:
CREATE TABLE project(
id INTEGER PRIMARY KEY,
name text
);
CREATE TABLE flag(
id INTEGER PRIMARY KEY,
name text
);
CREATE TABLE project_flag(
project_id integer not null,
flag_id integer not null,
FOREIGN KEY(project_id) REFERENCES project(id),
FOREIGN KEY(flag_id) REFERENCES flag(id)
);
INSERT INTO project (id,name) VALUES (1,'project1');
INSERT INTO project (id,name) VALUES (2,'project2');
INSERT INTO project (id,name) VALUES (3,'project3');
INSERT INTO flag (id,name) VALUES (1,'flag1');
INSERT INTO flag (id,name) VALUES (2,'flag2');
INSERT INTO flag (id,name) VALUES (3,'flag3');
INSERT INTO flag (id,name) VALUES (4,'flag4');
INSERT INTO project_flag (project_id,flag_id) VALUES (1,1);
INSERT INTO project_flag (project_id,flag_id) VALUES (1,2);
INSERT INTO project_flag (project_id,flag_id) VALUES (1,3);
INSERT INTO project_flag (project_id,flag_id) VALUES (1,4);
INSERT INTO project_flag (project_id,flag_id) VALUES (2,1);
INSERT INTO project_flag (project_id,flag_id) VALUES (2,4);
And here is my Perl (Mojolicious) code:
#!/usr/bin/env perl
use Mojolicious::Lite;
use Schema;
helper db => sub {
return Schema->connect('dbi:SQLite:test.db');
};
get '/' => sub {
my $self = shift;
my $rs = $self->db->resultset('Project')->search(
{ 'me.name' => 'project3' },
{
join => { 'project_flags' => 'flag' },
select => ['me.name', 'flag.name'],
as => ['project', 'flag']
}
);
$rs->result_class('DBIx::Class::ResultClass::HashRefInflator');
$self->render( json => [ $rs->all ] );
};
app->start;
And here's the JSON output (pretty print) from project1 (has flags related to it):
[
{
"project":"project1",
"flag":"flag1"
},
{
"flag":"flag2",
"project":"project1"
},
{
"project":"project1",
"flag":"flag3"
},
{
"flag":"flag4",
"project":"project1"
}
]
And here is JSON for project3, with no relationship to any flags:
[
{
"project":"project3",
"flag":null
}
]
I put the files on Github, so you can check them out if you'd like.
In your given situation, say they've typed the word 'c++' into the filter, and you want to return everything that has been tagged 'c++', then:
my $rs = $self->db->resultset('Tag')->search(
{ 'me.name' => 'c++' },
{
join => { 'project_flags' => 'project' },
select => ['me.name', 'project.name'],
as => ['tag', 'project']
}
);
$rs->result_class('DBIx::Class::ResultClass::HashRefInflator');
$self->render( json => [ $rs->all ] );
If you wanted to return all columns, use prefetch rather than join. Also, if you'd like to support the Autosearch functionality, change search to search_like, like so:
my $rs = $self->db->resultset('Tag')->search_like(
{ 'me.name' => $search_filter.'%' },
I hope that if I did not answer your question what I have given is at least a push in the right direction.

Role not found error

I'm trying to setup ZfcUser with BjyAuthorize. I'm getting the following error when trying to access the guarded route "/user".
Fatal error: Uncaught exception 'Zend\Permissions\Acl\Exception\InvalidArgumentException' with message 'Role '3' not found' in /home/brian/dev/ptapp/app/vendor/zendframework/zendframework/library/Zend/Permissions/Acl/Role/Registry.php:106
Stack trace:
#0 /home/brian/dev/ptapp/app/vendor/zendframework/zendframework/library/Zend/Permissions/Acl/Role/Registry.php(67): Zend\Permissions\Acl\Role\Registry->get('3')
#1 /home/brian/dev/ptapp/app/vendor/zendframework/zendframework/library/Zend/Permissions/Acl/Acl.php(112): Zend\Permissions\Acl\Role\Registry->add(Object(Zend\Permissions\Acl\Role\GenericRole), Array)
#2 /home/brian/dev/ptapp/app/vendor/bjyoungblood/bjy-authorize/src/BjyAuthorize/Service/Authorize.php(277): Zend\Permissions\Acl\Acl->addRole('bjyauthorize-id...', Array)
#3 /home/brian/dev/ptapp/app/vendor/bjyoungblood/bjy-authorize/src/BjyAuthorize/Service/Authorize.php(90): BjyAuthorize\Service\Authorize->load()
#4 /home/brian/dev/ptapp/app/vendor/bjyoungblood/bjy-authorize/src/BjyAuthorize/Service/Authorize.php(239) in /home/brian/dev/ptapp/app/vendor/zendframework/zendframework/library/Zend/Permissions/Acl/Role/Registry.php on line 69
My database tables were created with the provided schema.sql in the bjyauthorize repository, which contains the following code:
CREATE TABLE IF NOT EXISTS `user_role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`roleId` varchar(255) NOT NULL,
`is_default` tinyint(1) NOT NULL,
`parent_id` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `user_role_linker` (
`user_id` int(11) unsigned NOT NULL,
`role_id` int(11) NOT NULL,
PRIMARY KEY (`user_id`,`role_id`),
KEY `role_id` (`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
;
With entries:
user_role
id | roleId | is_default | parent_id
---------------------------------------------
1 admin 0 therapist
2 therapist 0 patient
3 patient 0 user
4 guest 1 NULL
5 user 0 NULL
user_role_linker
user_id role_id
-------------------
3 3
I had to modify my bjyauthorize.global.php file because the "role_id_field" and the "parent_role_field" value didn't match up with sql schema provided. It looks like this:
<?php
return array(
'bjyauthorize' => array(
'default_role' => 'guest',
'identity_provider' => 'BjyAuthorize\Provider\Identity\ZfcUserZendDb',
'role_providers' => array(
'BjyAuthorize\Provider\Role\ZendDb' => array(
'table' => 'user_role',
'role_id_field' => 'roleId',
'parent_role_field' => 'parent_id',
),
),
'guards' => array(
'BjyAuthorize\Guard\Route' => array(
array('route' => 'zfcuser', 'roles' => array('user')),
array('route' => 'zfcuser/logout', 'roles' => array('user')),
array('route' => 'zfcuser/login', 'roles' => array('guest')),
array('route' => 'zfcuser/register', 'roles' => array('guest')),
// Below is the default index action used by the ZendSkeletonApplication
array('route' => 'home', 'roles' => array('guest', 'user')),
),
),
),
);
And my application.config.php looks like this:
<?php
return array(
'modules' => array(
'Application',
'ZfcBase',
'ZfcUser',
'User',
'BjyAuthorize',
),
'module_listener_options' => array(
'module_paths' => array(
'./module',
'./vendor',
),
'config_glob_paths' => array(
'config/autoload/{,*.}{global,local}.php',
),
),
);
Where the module "User" Is my custom ZfcUser Entity.
Any ideas where the problem is? I'm pretty new to ZF2 and zfc so thanks for your help!
EDIT: I should note that when I'm not logged in, I correctly get a 403 when trying to access /user, it's when I'm logged in that I receive this message. I receive it when trying to access any route (except invalid routes, I get a 404)
Based on first Comment, following sql works,
the same problem exists on parent_id, you need to change it, too:
CREATE TABLE IF NOT EXISTS `user_role` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`role_id` VARCHAR(255) NOT NULL,
`is_default` TINYINT(1) NOT NULL DEFAULT 0,
`parent_id` VARCHAR(255) NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `unique_role` (`role_id` ASC),
INDEX `idx_parent_id` (`parent_id` ASC),
CONSTRAINT `fk_parent_id` FOREIGN KEY (`parent_id`) REFERENCES `user_role` (`role_id`) ON DELETE SET NULL
) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `user_role_linker` (
`user_id` INT UNSIGNED NOT NULL,
`role_id` VARCHAR(255) NOT NULL,
PRIMARY KEY (`user_id`, `role_id`),
INDEX `idx_role_id` (`role_id` ASC),
INDEX `idx_user_id` (`user_id` ASC),
CONSTRAINT `fk_role_id` FOREIGN KEY (`role_id`) REFERENCES `user_role` (`role_id`) ON DELETE CASCADE,
CONSTRAINT `fk_user_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`user_id`) ON DELETE CASCADE
) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_unicode_ci;
The problem seems to be with the provided sql schema. In the user_role_linker table, change the role_id field to a VARCHAR. When making entries to this table, user_id should correspond to the user's numerical id, but the role_id should be the text id of the "roleId" field in the user_role table.

CakePHP 2.2 with PostgreSQL Failed new row insert - Database Error: Undefined table: 7 ERROR: relation "table_id_seq" does not exist

My problem is as follows.
After deleting multiple rows from table, inserting new record into same table results in error.
Database Error
Error: SQLSTATE[42P01]:
Undefined table: 7 ERROR: relation "order_details_id_seq" does not exist
Table
CREATE TABLE schema.order_details (
id serial NOT NULL,
order_id integer NOT NULL,
field_1 integer,
field_2 real,
field_3 character varying(15),
CONSTRAINT order_details_pkey PRIMARY KEY (id )
)
WITH (
OIDS=FALSE
);
Insert is
INSERT INTO "schema"."order_details" ("order_id", "field_1", "field_2", "field_3")
VALUES (37, 1, 2, 'value');
Sequence "schema"."order_details_id_seq" in used schema exists.
CREATE SEQUENCE schema.order_details_id_seq
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 37
CACHE 1;
Models.
// Model
class Order extends AppModel {
public $useDbConfig = 'other_data';
public $hasMany = array(
'OrderDetail' => array(
'className' => 'OrderDetail',
'foreignKey' => 'order_id',
'dependent' => true,
'order' => array(
'OrderDetail.order_id',
'OrderDetail.field_1'
))
);
class OrderDetail extends AppModel {
public $useDbConfig = 'other_data';
public $belongsTo = array(
'Order' => array(
'className' => 'Order',
'foreignKey' => 'order_id',
'dependent' => true
),
// model Order save code on recreation of order
$this->OrderDetail->deleteAll(array('OrderDetail.order_id' => $this->id));
At this point tried to insert $this->OrderDetail->query('VACUUM FULL ANALYZE order_details'); with no effect
foreach ($details as $d) {
$this->OrderDetail->create();
$this->OrderDetail->save($d /*array(
'order_id' => $this->id,
'field_1' => 1,
'field_2' => 2,
'field_3' => 'value'
)*/);
}
I get error on first foreach loop.
Weirdest thing is that problem appears and disappears after some time randomly.
Any suggestions on what it could be and how to get rid of it?
Currently solved problem using code.
$this->Order->id = $id;
$this->Order->delete();
It fires 2 queries for each row (100 extra in my case!) of delete statements instead of two in case of
$this->OrderDetail->deleteAll(array('OrderDetail.order_id' => $id));
So for this time it has space for improvement.
EDIT: Currently code works as it should with tweaked DboSource.
It seems that cake was looking in public schema for sequence where it is not located.
Fixed it by tweaking to include schema name in last insert getter inf file Model/Datasource/DboSource.php create method with this diff
## -1006,7 +1006,7 ##
if ($this->execute($this->renderStatement('create', $query))) {
if (empty($id)) {
- $id = $this->lastInsertId($this->fullTableName($model, false, false), $model->primaryKey);
+ $id = $this->lastInsertId($this->fullTableName($model, false, true), $model->primaryKey);
}
$model->setInsertID($id);
$model->id = $id;
I know that modifying core is not the way to go, but as long as it is working it is fine with me.
This happened to me because I modified the name of the table, but PostgreSQL did not change the name of the sequences. Knowing this, I changed the name of the sequences that affected this table and it was resolved.
To prevent this error, use this convention to name your sequence when using cakephp: table_name_id_seq. For example:
table name: user
sequence name should be: user_id_seq
If you alredy have sequences, you can rename it in posgres like this
alter sequence user_seq rename to user_id_seq
I'm not a fun of this way to name sequence but it prenvent this kind of errors in my case