Enforce 1:0..1 relationship with EF6 Database First - sql-server

In my model, I have three tables, Storage, Haul and StoragePlace. One storage can either be a place or haul. For the StoragePlace, I already achieved a 1:0..1 relationship. The problem is the Haul entity.
CREATE TABLE dbo.Haul
(
ID INT NOT NULL PRIMARY KEY IDENTITY,
ID_Storage INT NOT NULL UNIQUE,
Arrival DATETIME NOT NULL DEFAULT getdate(),
Depature DATETIME NULL,
CONSTRAINT FK_Haul_to_Storage FOREIGN KEY (ID_Storage) REFERENCES Storage(ID) ON DELETE CASCADE
)
GO
/** --- See edit below --
CREATE UNIQUE NONCLUSTERED INDEX UQX_Storage
ON Haul(ID_Storage)
WHERE ID_Storage IS NOT NULL;
GO
**/
--------------------------------------------------
CREATE TABLE dbo.Storage
(
ID INT NOT NULL PRIMARY KEY IDENTITY,
Description1 NVARCHAR(100) NULL,
Description2 NVARCHAR(100) NULL,
AddedBy NVARCHAR(50) NOT NULL
)
--------------------------------------------------
CREATE TABLE dbo.StoragePlace
(
ID INT NOT NULL PRIMARY KEY,
ID_PlantArea INT NOT NULL,
CONSTRAINT FK_StoragePlace_to_Storage FOREIGN KEY (ID) REFERENCES Storage(ID) ON DELETE CASCADE,
CONSTRAINT FK_StoragePlace_to_PlantArea FOREIGN KEY (ID_PlantArea) REFERENCES PlantArea(ID) ON DELETE CASCADE
)
My thought was, that UQX_Storage would trigger EF6 to accept a 1:0..1 relationship between Haul and Storage. Certainly, this doesn't work; it still insists on a 1:* relationship, which, from my understanding, shall not be possible with this model above.
How can I enforce the intended 1:0..1 relationship between Haul and Storage?
EDIT:
I just realized, that the ID_Storage field can never be NULL, so I replaced the UQX_Storage "constraint" with a simple ID_Storage INT NOT NULL UNIQUE,. However, that didn't solve the problem either.

Related

Update/Delete violate foreign key on either side

I have two tables, below are the strutures
CREATE TABLE IF NOT EXISTS nl_address (
id int NOT NULL GENERATED BY DEFAULT AS IDENTITY,
address_text varchar(100),
pincode varchar(6),
city_id int NOT NULL,
state_id int NOT NULL,
country_id int NOT null,
is_active boolean default true,
PRIMARY KEY (id),
CONSTRAINT fk_city_id FOREIGN KEY(city_id) REFERENCES nl_city(id),
CONSTRAINT fk_state_id FOREIGN KEY(state_id) REFERENCES nl_state(id),
CONSTRAINT fk_country_id FOREIGN KEY(country_id) REFERENCES nl_country(id)
);
CREATE TABLE IF NOT EXISTS nl_customer (
cust_id int NOT NULL,
prefix varchar(10) default 'CUST-',
suffix varchar(2),
org_name varchar(100) NOT NULL,
domain_name varchar(100) NOT NULL,
pan_number varchar(10) NOT null,
pri_contact varchar(10) NOT NULL,
pri_number varchar(10) NOT NULL,
pri_email varchar(30) NOT NULL,
sec_contact varchar(10),
sec_number varchar(10),
sec_email varchar(30),
is_active boolean default true,
addr_id int not null,
created_date date,
created_by varchar(10),
updated_date date,
updated_by varchar(10),
PRIMARY KEY (cust_id),
CONSTRAINT fk_address_id FOREIGN KEY(addr_id) REFERENCES nl_address(id)
);
The problem is, neither I am able to update or delete
If i am trying to update record in nl_address, I got an violation error that the field is used inside `nl_customer.
If i tried to update from nl_customer, then I got an violation error that the field is used inside nl_address
It was originated, when JPA trying to persist the data, I have inserted a dummy data with id 1, when JPA trying to insert another record then it throws
.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "nl_address_pkey"
Detail: Key (id)=(1) already exists.
It seems there is something wrong with the table structure, any help appreciated
Actually this is common that you cannot update or delete that belong to primary/foreign key if you generate duplicates, as all values should be unique (i.e. if you have already id=1 and update id=2 to id=1, you will get the error you mentioned) and because a foreign key construct is a specific relationship it should be clarified what will happen with this relationship.
In case of 'nl_address' you used 'GENERATED BY DEFAULT AS IDENTITY' which have the same purpose as SERIAL (i.e. auto increment), but it is more compliant with SQL standard. (I assume you are also aware of difference between GENERATED BY DEFAULT and GENERATED ALWAYS)
However, you can specify the sequence in order to ensure the proper auto increment functionality.
ALTER TABLE nl_address
ALTER COLUMN "id"
DROP IDENTITY IF EXISTS;
ALTER TABLE nl_address
ALTER COLUMN "id"
ADD GENERATED BY DEFAULT AS IDENTITY (START WITH 1 INCREMENT 1);
If you use UPDATE or DELETE on FOREIGN KEY construct ensure what should happen with relationship:
[CONSTRAINT fk_name]
FOREIGN KEY(fk_columns)
REFERENCES parent_table(parent_key_columns)
[ON DELETE delete_action]
[ON UPDATE update_action]
/* as delete_action or update_action you can use e.g. SET NULL, RESTRICT or CASCADE;
so ensure what happen with records in related table*/

SQL Server : two foreign keys pointing to one table. Error: Introducing FOREIGN KEY constraint may cause cycles or multiple cascade paths

I'm getting the error:
Msg 1785, Level 16, State 0, Line 238
Introducing FOREIGN KEY constraint 'FK_Studios_Members_HeadId' on table 'Studios' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Below is a simplified version of the two tables I'm having problems with:
CREATE TABLE [Members]
(
[MemberId] int NOT NULL IDENTITY
)
CREATE TABLE [Studios]
(
[StudioId] int NOT NULL IDENTITY,
[HeadId] int,
[OwnerId] int,
CONSTRAINT [PK_Studios] PRIMARY KEY ([StudioId]),
CONSTRAINT [FK_Studios_Members_OwnerId]
FOREIGN KEY ([OwnerId]) REFERENCES [Members] ([MemberId])
ON DELETE SET NULL,
CONSTRAINT [FK_Studios_Members_HeadId]
FOREIGN KEY ([HeadId]) REFERENCES [Members] ([MemberId])
ON DELETE SET NULL
)
I found that if I switch the order of the two FK's, it will always error on the second one. I don't see why this will cause a cascading problem since both have the "ON DELETE SET NULL".
This is being generated by EF Core code-first, so I need the relationships and can't just hack in trigger in the backend.
What am I missing?
I'm not sure of an answer that will work with what you have there and I'm not sure how set in stone your design is...but as an alternate design that I don't think would have the same issue have you considered a separate middle relationship table?
One benefit of this approach is it allows you to have multiple members at each position.
CREATE TABLE [Members]
(
[MemberId] int NOT NULL IDENTITY
)
CREATE TABLE [Studios]
(
[StudioId] int NOT NULL IDENTITY,
CONSTRAINT [PK_Studios] PRIMARY KEY ([StudioId]),
)
--Contains Owner, Head, etc.
CREATE TABLE [Relationships]
(
[RelationshipId] int NOT NULL IDENTITY,
[RelationshipId] nvarchar(20) NOT NULL
)
CREATE TABLE [StudioMemberRelationships]
(
[StudioMemberRelationshipId] int NOT NULL IDENTITY,
[StudioId] int NOT NULL,
[MemberId] int NOT NULL,
[RelationshipTypeId] int NOT NULL,
CONSTRAINT [FK_StudioMemberRelationships_StudioId]
FOREIGN KEY ([StudioId]) REFERENCES [Studios] ([StudioId])
ON DELETE SET NULL,
CONSTRAINT [FK_StudioMemberRelationships_MemberId]
FOREIGN KEY ([MemberId]) REFERENCES [Members] ([MemberId])
ON DELETE SET NULL,
CONSTRAINT [FK_StudioMemberRelationships_RelationshipId]
FOREIGN KEY ([RelationshipId]) REFERENCES [Relationships] ([RelationshipId])
ON DELETE SET NULL
)

SQL Server & Visual Studio - Insert Data in tables doesn't work

I want to insert my tables from my SQL Server Management Studio code with data via Visual Studio.
But it doesn't work. The ID of my table doesn't get a value automatically (but I have command it with identity(1,1)) and an error appears that it stands in conflict with a foreign-key-constraint.
create table [ProduktZahlungFENutzer]
(
ID int PRIMARY KEY IDENTITY(1,1) NOT NULL,
Endpreis decimal(3, 2)
);
CREATE TABLE [FHAngehörige]
(
FHAngehörigeID INT NOT NULL IDENTITY(1,1)
PRIMARY KEY Constraint fhA_feN
REFERENCES FENutzer(FENutzerID),
Name VARCHAR(50) NOT NULL,
Fachbereich INT NOT NULL,
Email VARCHAR(50) NOT NULL UNIQUE
)
CREATE TABLE [FENutzer]
(
FENutzerID INT IDENTITY(1,1) NOT NULL
PRIMARY KEY constraint t_nutzer
references ProduktZahlungFENutzer(ID),
Aktiv INT NOT NULL,
LetzterLogin datetime NOT NULL DEFAULT GETDATE(),
BENutzerID int NOT NULL
constraint FENutzer_BENutzer
foreign key references BENutzer(BENutzerID),
auth_id int not null
constraint FENutzer_auth
foreign key references auth2(id)
)
Please help
You have established a reference
FHAngehörigeID INT NOT NULL IDENTITY(1,1) PRIMARY KEY Constraint fhA_feN
REFERENCES FENutzer(FENutzerID),
This means that you need a record in your table FENutzer.FENutzerID that match FHAngehörigeID, in this case you cannot use IDENTITY
Your construction makes no sense - this way, you're creating two tables that depend on each other, at the primary key level - so you would have to have an existing entry in FENutzer in order to insert a new row into FHAngehörige, and this at the same time is only possible if you already have an existing row in FHAngehörige to insert the row in FEnutzer.....
You need to clean this up:
both tables need a primary key and the int identity(1,1) is a very good choice
one of the tables must reference the other, but with a normal foreign key attribute - not on the primary key.....
Since you've not given any indication as to which of the tables is the "main" table and which the "child/auxiliary" table, I'm just picking one over the other - so your table structure should be something like:
CREATE TABLE dbo.FHAngehoerige
(
FHAngehoerigeID INT NOT NULL IDENTITY(1,1)
CONSTRAINT PK_FHAngehoerige PRIMARY KEY CLUSTERED,
Name VARCHAR(50) NOT NULL,
Fachbereich INT NOT NULL,
Email VARCHAR(50) NOT NULL UNIQUE
)
CREATE TABLE dbo.FENutzer
(
-- define the PK for the table
FENutzerID INT IDENTITY(1,1) NOT NULL
CONSTRAINT PK_FENutzer PRIMARY KEY CLUSTERED,
-- define the **foreign key** to the main table
FHAngehoerigeID INT NOT NULL
CONSTRAINT FK_FENutzer_FHAngehoerige
FOREIGN KEY REFERENCES dbo.FHAngehoerige(FHAngehoerigeID),
Aktiv INT NOT NULL,
LetzterLogin datetime NOT NULL DEFAULT GETDATE(),
BENutzerID int NOT NULL
constraint FENutzer_BENutzer
foreign key references BENutzer(BENutzerID),
auth_id int not null
constraint FENutzer_auth
foreign key references auth2(id)
)
Also: I would strongly recommend (from my own personal, bad experience) to AVOID any special characters like umlauts or accents or anything like that in table and column names.....

How to solve multiple cascade paths?

In my database, I have a Person and Member table. The Member table has 2 foreign keys which both reference the same column in the People Table. The constraints look like this:
CONSTRAINT [FK_Members_People_1]
FOREIGN KEY ([PersonID])
REFERENCES [People].[People]([ID])
ON DELETE CASCADE
ON UPDATE NO ACTION,
CONSTRAINT [FK_Members_People_2]
FOREIGN KEY ([EnquiryTakenBy])
REFERENCES [People].[People]([ID])
ON DELETE SET NULL
ON UPDATE NO ACTION
The error I get is as follows:
Introducing FOREIGN KEY constraint 'FK_Members_People_2' on table 'Members' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
How would I go about solving this?
Basically this is the behaviour I'm trying to get:
When the record referenced by PersonID is removed. I need it to delete all child records in other tables. (There's 8 child tables)
When the record referenced by EnquiryTakenBy is deleted. I need EnquiryTakenBy to be set to null.
EDIT: Table structure is as follows:
CREATE TABLE [People].[People]
(
[ID] INT NOT NULL IDENTITY,
[PersonType] INT NOT NULL,
[Forename] VARCHAR(16) NOT NULL,
[Surname] VARCHAR(32) NOT NULL,
[Gender] CHAR(1) NOT NULL,
[DateOfBirth] DATE NULL,
[HobbiesAndInterests] VARCHAR(256) NULL,
[AdditionalInformation] VARCHAR(512) NULL,
[LocalCentre] INT NOT NULL DEFAULT 0,
CONSTRAINT [PK_People] PRIMARY KEY ([ID]),
CONSTRAINT [FK_People_PersonType]
FOREIGN KEY ([PersonType])
REFERENCES [Lookups].[PersonTypes]([ID])
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT [FK_People_Centres]
FOREIGN KEY ([LocalCentre])
REFERENCES [Lookups].[Centres]([ID])
ON DELETE CASCADE
ON UPDATE CASCADE
)
CREATE TABLE [People].[Members]
(
[PersonID] INT NOT NULL,
[IsActive] BIT NOT NULL DEFAULT 0,
[Issues] VARCHAR(500) NULL,
[InTreatment] BIT NOT NULL DEFAULT 0,
[ProblemSubstance] VARCHAR(64) NOT NULL,
[WantsHelpWith] VARCHAR(128) NULL,
[EnquiryTakenBy] INT NOT NULL,
[IsVolunteer] BIT NOT NULL DEFAULT 0,
CONSTRAINT [PK_Members] PRIMARY KEY ([PersonID]),
CONSTRAINT [FK_Members_People_1]
FOREIGN KEY ([PersonID])
REFERENCES [People].[People]([ID])
ON DELETE CASCADE
ON UPDATE NO ACTION,
CONSTRAINT [FK_Members_People_2]
FOREIGN KEY ([EnquiryTakenBy])
REFERENCES [People].[People]([ID])
ON DELETE SET NULL
ON UPDATE NO ACTION
)
Ok, found a solution. Apparently my problem was something to do with SQL Server didn't know which constraint took precedence, so I replaced the second foreign key constraint with this trigger:
CREATE TRIGGER Member_UpdateEnquiryID ON People.People
AFTER DELETE
AS
BEGIN
DECLARE #id int = (select id from deleted);
UPDATE People.Members
SET EnquiryTakenBy = NULL
where EnquiryTakenBy = #id
END

Foreign Key Relationship with one of Multiple Tables

I have a language map table that each entry has the possibility of a foreign key relationship with a few different tables. What is the best schema to deal with this configuration?
Tables: LanguageMap, TableA, TableB
These are the two possibility:
1. Lookup Column Method - No Foreign Key Constraints:
Create Table LanguageMap (
Id int not null primary key,
Language nvarchar not null,
Value nvarchar not null,
Type nvarchar not null, -- 'TableA', 'TableB', etc.
ForeignTableId int not null -- Is Foreign key to another table dependent on the type of the row.
)
2. Multiple Foreign Key Columns
create Table LanguageMap(
Id int not null primary key,
Language nvarchar not null,
Value nvarchar not null,
Type nvarchar not null, -- 'Activity', 'Verb', etc.
TableAId int null,
TableBId int null
)
alter table LanguageMap add constraint FK_LanguageMap_TableA
foreign key (TableAId) references TableA (Id)
alter table LanguageMap add constraint FK_LanguageMap_TableA
foreign key (TableBId) references TableB (Id)
alter table LanguageMap add constraint CK_LanguageMap_OneIsNotNull
check (TableAId is not null or TableBId is not null)
go
alter table LanguageMap add constraint CK_LanguageMap_OneIsNull
check (TableAId is null or TableBId is null)
go
The foreign key constraints are based on Foreign Key for either-or column?
There is another alternative, called "Shared Primary Key". You can look this up. If TableA, TableB, TableC, etc. all "inherit" their PK as a copy of the PK from some Master table, called "TableMaster" for example, then you can just use that as an FK in LanguageMap.
The correct joins will select the correct instances.
The shared primary key is often used in conjunction with a design pattern called "Class Table Inheritance". Without knowing what TableA, TableB, TableC, etc. are about, I can't say whether Class Table Inheritance is relevant to your case.
In any event, look up both "Shared Primary Key" and "Class Table Inheritance" for further reading.
There are tags with those names in this area.

Resources