Entity Framework constraints cardinality - visual-studio-2010

How can I make a constraint on Entity Framework to read a foreign key relation from table cars to vehicle (for example) as 0..1 -> 1 instead of * -> 1?
I have tables
create TABLE [dbo].[Vehicles](
[Id] [int] IDENTITY(1,1) NOT NULL primary key,
<rest of the columns>
)
create TABLE [dbo].[Cars](
[Id] [int] NOT NULL,
<rest of the columns>
)
and foreign key:
alter table [Cars] add foreign key(id) references [Vehicles](id)
when I create a model from the DB, it is created as * -> 1 an I cant change:
I know I manually change the association between the two entities but it doesn't matter because it doesn't change the constraint
I need to do that to set the baseType property of Cars to Vehicle to Implement a Inheritance.
Currently I'm getting this error:
Multiplicity is not valid in Role 'BoatsTPT' in relationship
'FK__BoatsTPT__Id__117F9D94'. Because the Dependent Role refers to the
key properties, the upper bound of the multiplicity of the Dependent
Role must be 1.

You must first make Id column in your Cars table a primary key otherwise it is not one-to-one relation.

Related

Oracle: create a partition by reference (partition by reference(fk)) on non referenced table

We have realized that we need to use Oracle (12 c) interval partitioning.We have an hierarchical entity model with lots of #OneToMany relationships.We want to use "partitioning by range" (day,month... ) on the "parent/root" entity (A) and "partition by reference" on all child entities (B).
From the Oracle documentation: "Reference partitioning allows the partitioning of two tables related to one another by referential constraints. The partitioning key is resolved through an existing parent-child relationship, enforced by enabled and active primary key and foreign key constraints." The problem is that child entities (B) can refer to other entities ( C) that they don't have any link with the "parent/root" entity (A). I can create partitions on A and on B but when I want to drop the partition on A ( partition on B on cascade), I get an error integrity error and it fails. it works only if I delete all records on C and B and then partition them. I don't want to do that as it's not efficient and slow compared to dropping partitions directly
Please is there a way to create a partition on table C based on A(creation_date) without adding any foreign constraint between A and C?
Small example to illustrate the case
A - parent entity
B - child entity to A
C - child entity to B
create table
A (
id number primary key,
creation_date date
)
partition by range (creation_date)
INTERVAL(NUMTOYMINTERVAL(1, 'MONTH'))
(
partition p1 values less than (to_date('20180501','yyyymmdd'))
);
create table
B (
id number primary key,
value varchar2(5),
a_id number not null,
constraint fk_ba foreign key (a_id) references A
)
partition by reference(fk_ba);
create table
C (
id number primary key,
code varchar2(5),
b_id number not null,
constraint fk_cb foreign key (b_id) references B
);
It was not clear in the documentation that partition by reference is transitive ( A->B->C). I have discovered it by testing. we can create table C "partition by reference (fk_cb)" with the result that when we drop A partition the matching B and C partitions get dropped.

Tried to have recursive relation

I use oracle and I try to have a recursive relation
CREATE TABLE "EVENT"
(
"EVENT_ID" NUMBER(18) NOT NULL, //primary key
"NAME" VARCHAR(20) NULL,
"RELATED_EVENT_ID" NUMBER(18) NULL //foreign key
);
Event 1 parent is Event 2....
When I try to create this table, I get this error.
ALTER TABLE "EVENT"
ADD CONSTRAINT "FK_RELATED_EVENT_ID"
FOREIGN KEY ("RELATED_EVENT_ID") REFERENCES "EVENT" ("RELATED_EVENT_ID")
Error report -
SQL Error: ORA-02270: no matching unique or primary key for this column-list
02270. 00000 - "no matching unique or primary key for this column-list"
*Cause: A REFERENCES clause in a CREATE/ALTER TABLE statement
gives a column-list for which there is no matching unique or primary
key constraint in the referenced table.
*Action: Find the correct column names using the ALL_CONS_COLUMNS
catalog view
You have two problems:
There is no primary key constraint on this table.
The foreign key constraint you defined has RELATED_EVENT_ID referencing RELATED_EVENT_ID. I suspect that was just a typo.
Change your table definition to:
CREATE TABLE EVENT
(EVENT_ID NUMBER
NOT NULL
CONSTRAINT PK_EVENT
PRIMARY KEY
USING INDEX,
NAME VARCHAR2(20),
RELATED_EVENT_ID NUMBER);
Then add the foreign key constraint as
ALTER TABLE EVENT
ADD CONSTRAINT EVENT_FK1
FOREIGN KEY (RELATED_EVENT_ID) REFERENCES EVENT(EVENT_ID);
db<>fiddle here
EDIT
Note that the better way to handle this is to use a junction table, such as:
CREATE TABLE EVENT_EVENT
(EVENT_ID1 NUMBER
CONSTRAINT EVENT_EVENT_FK1
REFERENCES EVENT(EVENT_ID),
EVENT_ID2 NUMBER
CONSTRAINT EVENT_EVENT_FK2
REFERENCES EVENT(EVENT_ID),
CONSTRAINT PK_EVENT_EVENT
PRIMARY KEY (EVENT_ID1, EVENT_ID2)
USING INDEX);
Then you can drop the RELATED_EVENT_ID column from EVENT as you no longer need it.
According to oracle document :
Foreign key specifies that the values in the column must correspond to values in a
referenced primary key or unique key column or that they are NULL.
In your case, create primary key on column (EVENT_ID) and use it in reference clause as following:
ALTER TABLE "EVENT"
ADD CONSTRAINT "FK_RELATED_EVENT_ID"
FOREIGN KEY ("RELATED_EVENT_ID")
REFERENCES "EVENT" ("EVENT_ID") -- this
Now, use EVENT2's EVENT_ID as RELATED_EVENT_ID in EVENT1 record to make EVENT2 as parent of EVENT1.
Cheers!!

How to implement bidirectional relationship in Spring Spanner?

In code, I tried with #Interleaved in 1-many relationship at non-owning side to get child list. Could anyone help with below questions:
How to implement bidirectional relationship e.g. get parent from child for 1-1, 1-many relationship
Regarding many-many relationship, what are best practices to implement it and how to implement bidirectional relationship for it.
Thank you very much.
Cloud Spanner currently doesn't offer a way to enforce foreign-key constraints between non-interleaved tables. You will have to enforce such constraints in your application logic. You could use DML statements in Cloud Spanner(that come with the ability to read-your-writes in a Cloud Spanner transaction) to enforce these constraints at insert time by inserting into your tables as follows:
INSERT INTO Referenced(key1,value1) VALUES ('Referenced','Value1');
INSERT INTO Referencing(key2, value2, key1)
SELECT 'Referencing', 'Value2', key1 FROM Referenced WHERE
key1 = 'Referenced';
Running the two statements in a read-write transaction will ensure that the PK-FK relationship between the Referenced and Referencing table is always maintained at insert time. You may have to similarly modify update requests/SQL update statements in your application logic to enforce the PK-FK constraint for updates.
For a 1-many relationship, when using interleaved tables, then the child row's primary key already contains the primary key of its parent, so it is trivial to get the parent row.
CREATE TABLE parent (
parent_key INT64 NOT NULL,
...
) PRIMARY KEY (parent_key);
CREATE TABLE child (
parent_key INT64 NOT NULL,
child_key INT64 NOT NULL,
...
) PRIMARY KEY (parent_key, child_key),
INTERLEAVE IN PARENT parent ON DELETE CASCADE;
If for some reason you do not have the key of the parent, and only the key of the child, then for efficiency you would need to create an index for the reverse lookup:
CREATE INDEX child_to_parent_index
ON child (
child_key
);
and force use of that index when performing the query for the parent:
SELECT
p.*
FROM
parent as p
JOIN
child#{FORCE_INDEX=child_by_id_index} AS c ON p.parent_key = c.parent_key
WHERE
c.child_key = #CHILD_KEY_VALUE;
Many-many relationships would have to be implemented using a 'mapping' table linking table1-key to table2-key.
You will also need a top-level index to get efficient reverse-lookups, and use the FORCE_INDEX directive as above in your queries.
And as #adi mentioned, foreign key constraints would have to be enforced by the application.
CREATE TABLE table1 (
table1_key INT64 NOT NULL,
...
) PRIMARY KEY (table1_key);
CREATE TABLE table2 (
table2_key INT64 NOT NULL,
...
) PRIMARY KEY (table2_key);
CREATE TABLE table1_table2_map (
table1_key INT64 NOT NULL,
table2_key INT64 NOT NULL,
) PRIMARY KEY (table1_key, table2_key);
CREATE INDEX table2_table1_map_index
ON table1_table2_map (
table2_key
) STORING (
table1_key
);
Your application would be responsible for keeping the referential integrity of the mapping table - deleting the mapping rows when rows in table1 or table2 are deleted
If you want to use interleaved tables, then if your application needs to perform bi-directional lookups, you may have to create 2 mapping tables - as a child of each parent, so that finding the mappings from both directions are equally efficient.
CREATE TABLE table1 (
table1_key INT64 NOT NULL,
...
) PRIMARY KEY (table1_key);
CREATE TABLE table2 (
table2_key INT64 NOT NULL,
...
) PRIMARY KEY (table2_key);
CREATE TABLE table1_table2_map (
table1_key INT64 NOT NULL,
table2_key INT64 NOT NULL,
) PRIMARY KEY (table1_key, table2_key),
INTERLEAVE IN PARENT table1 ON DELETE CASCADE;
CREATE TABLE table2_table1_map (
table2_key INT64 NOT NULL,
table1_key INT64 NOT NULL,
) PRIMARY KEY (table2_key, table1_key),
INTERLEAVE IN PARENT table2 ON DELETE CASCADE;
Note that the application needs to keep both of these mapping tables up to date -- ie when deleting a row from table1, the application has to get the referenced table2_key values and delete the mappings from the table2_table1_map (and vice versa).

one attribute referencing, attributes in two different tables

I have 4 tables
customer: CustomerID - primary key, name
Magazine: name - primary key, cost, noofissues
Newspaper: name - primary key, cost, noofissues
subscription: custID - references CustomerID of Customer, name, startdate, enddate
In the above, can I reference the name from subscription table to reference name from Magazine and name from Newspaper?
I have created the tables Customer, Newspaper and Magazine. I only need to create Subscription.
Can you do something like this?
CREATE TABLE subscription (
custID INT
CONSTRAINT subscription__custid__fk REFERENCES Customer( CustomerId ),
name VARCHAR2(50)
CONSTRAINT subscription__mag_name__fk REFERENCES Magazine( Name )
CONSTRAINT subscription__news_name__fk REFERENCES Newspaper( Name ),
startdate DATE
CONSTRAINT subscription__startdate__nn NOT NULL,
enddate DATE
);
Yes, you can and you will have two foreign keys on the same column pointing to different tables but if the value in the column is non-null then it will expect there to be a matching name in both the magazines table and the newspapers table - which is probably not what you are after.
Can you have a foreign key that asks can the value be in either exclusively in this table or that table (but not in both)? No.
But you can re-factor your database so you merge the newspapers and magazines tables into a single table (which you can then easily reference); like this:
CREATE TABLE customer (
CustomerID INT
CONSTRAINT customer__CustomerId__pk PRIMARY KEY,
name VARCHAR2(50)
CONSTRAINT customer__name__nn NOT NULL
);
CREATE TABLE Publications (
id INT
CONSTRAINT publications__id__pk PRIMARY KEY,
name VARCHAR2(50)
CONSTRAINT publications__name__nn NOT NULL,
cost NUMBER(6,2)
CONSTRAINT publications__cost__chk CHECK ( cost >= 0 ),
noofissues INT,
type CHAR(1),
CONSTRAINT publications__type__chk CHECK ( type IN ( 'M', 'N' ) )
);
CREATE TABLE subscription (
custID INT
CONSTRAINT subscription__custid__fk REFERENCES Customer( CustomerId ),
pubID INT
CONSTRAINT subscription__pubid__fk REFERENCES Publications( Id ),
startdate DATE
CONSTRAINT subscription__startdate__nn NOT NULL,
enddate DATE
);
If you are asking whether you can create a foreign key constraint on subscription that references either the newspaper table or the magazine table, the answer is no, you cannot. A foreign key must reference exactly one primary key.
Since magazine and newspaper have the same set of attributes, the simple option is to combine them into a single periodical table with an additional periodical_type column to indicate whether it is a magazine or a newspaper. You could then create your foreign key to the periodical table.
Although it probably won't make sense in this particular example, you could also have separate columns in subscription for magazine_name and newspaper_name and create separate foreign key constraints on those columns along with a check constraint that ensured that exactly one of the values was non-NULL. That might make sense if the two different parent tables had radically different attributes.
Not related to your question but as a general bit of advice, I wouldn't use the name as the primary key. In addition to being rather long, names tend to change over time and names aren't necessarily unique. I would use a different attribute for the key, potentially a synthetic primary key generated from a sequence.

How to use Oracle "partitioning by reference" in tables with 2 foreign keys?

A little bit late in the project we have realized that we need to use Oracle (11G) partitioning both for performance and admin of the data.
We have an hierarchical entity model with lots of #OneToMany and #OneToOne relationships, and some entities are referenced from 2 or more other entities.
We want to use "partitioning by range" (month) on the "parent/root" entity and "partition by reference" on all child entities. After a year we will move the oldest month partition to an archive db. It's a 24-7 system so the data continuously grows.
From the Oracle documentation: "Reference partitioning allows the partitioning of two tables related to one another by referential constraints. The partitioning key is resolved through an existing parent-child relationship, enforced by enabled and active primary key and foreign key constraints."
Is it possible to use "partition by reference" on a table when there are 2 foreign keys and one of them can be null?
(From what I read you have to use "not null" on the foreign key for "partition by reference")
A small example to illustrate the problem:
A - parent entity
B - child entity to A
C - child entity to A or B
create table
A (
id number primary key,
adate date
)
partition by range (adate) (
partition p1 values less than (to_date('20130501','yyyymmdd')),
partition p2 values less than (to_date('20130601','yyyymmdd')),
partition pm values less than (maxvalue)
);
create table
B (
id number primary key,
text varchar2(5),
a_id number not null,
constraint fk_ba foreign key (a_id) references A
)
partition by reference(fk_ba);
create table
C (
id number primary key,
text varchar2(5),
a_id number not null, -- NOT POSSIBLE as a_id or b_id will be null..
b_id number not null, -- NOT POSSIBLE as a_id or b_id will be null..
constraint fk_ca foreign key (a_id) references A,
constraint fk_cb foreign key (b_id) references B
)
partition by reference(fk_ca)
partition by reference(fk_cb);
Thanks for any advice.
/Mats
You cannot partition by two foreign keys.
If A is parent of B and B is parent of C i would suggest partitioning C by fk_cb. weather you'l gain max pruning when joining A and C - thats an interesting question, why wont you run a test for us ?
question - why you have FK of A in table C. isn't A implied by the fk to B ?
(my guess, technically it's possible but oracle would have to access table B. i dont think he will do that so i think you wont get prunning).

Resources