A simple stored procedure that I want to handle with LINQ instead:
SELECT
CASE WHEN mg.MovieID IS NULL THEN 0 else 1 end as Selected ,
g.genreID, g.GenreName
FROM dbo.Genres g LEFT JOIN
(
SELECT MovieID, GenreID FROM [dbo].[MovieGenre] m
WHERE m.MovieID = #Movie
) MG
ON g.[GenreID] = mg.[GenreID]
ORDER BY g.GenreName
I think this should be simple and I think it would be a common requirement, yet I can't figure it out nor have I found a solution via searching the web.
The app is in WPF backed by an EF model. Since EF hides the join table I need LINQ syntax that can deal with the absence of the intermediary table.
Classic many-to-many with a simple join table: table 1:Movies, table 2: Genres, Join table: MovieGenres. In the UI the user selects a specfic movie. For that movie I want to bring back ALL the genres and a bool value indicating whether the genre has been assigned to the movie. Hours of attempting this in LINQ have failed me, so the solution is currently to have the stored procedure above generate the values for me. I won't always be abe to do this with a stored procedure and would love to see a LINQ solution.
Here's the actual SQL table structures
CREATE TABLE [dbo].[Genres](
[GenreID] [int] IDENTITY(1,1) NOT NULL,
[GenreName] [nvarchar](15) NOT NULL,
CONSTRAINT [PK_Genres] PRIMARY KEY CLUSTERED
(
[GenreID] ASC
)) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Movies](
[MovieID] [int] IDENTITY(1,1) NOT NULL,
[MovieTitle] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_Movies] PRIMARY KEY CLUSTERED
(
[MovieID] ASC
))
ON [PRIMARY]
GO
CREATE TABLE [dbo].[MovieGenre](
[MovieID] [int] NOT NULL,
[GenreID] [int] NOT NULL,
CONSTRAINT [PK_MovieGenre] PRIMARY KEY CLUSTERED
(
[MovieID] ASC,
[GenreID] ASC
)) ON [PRIMARY]
GO
ALTER TABLE [dbo].[MovieGenre] WITH CHECK ADD CONSTRAINT [FK_Genres] FOREIGN KEY([GenreID])
REFERENCES [dbo].[Genres] ([GenreID])
GO
ALTER TABLE [dbo].[MovieGenre] CHECK CONSTRAINT [FK_Genres]
GO
ALTER TABLE [dbo].[MovieGenre] WITH CHECK ADD CONSTRAINT [FK_Movies] FOREIGN KEY([MovieID])
REFERENCES [dbo].[Movies] ([MovieID])
GO
ALTER TABLE [dbo].[MovieGenre] CHECK CONSTRAINT [FK_Movies]
GO
This should do the trick.
use from and in with the navigation property for a join
DefaultIfEmpty to make it a left join
Using a ternary operator ? : for the case statement
Query:
var query = from g in context.Genres
from m in g.Movies.Where(x => x.MovieID == movieId)
.DefaultIfEmpty()
orderby g.GenreName
select new {
Selected = m == null ? 0 : 1,
g.genreID,
g.GenreName
};
Related
CREATE TABLE Flight (
FlightNo int NOT NULL PRIMARY KEY,
FlightDate Date,
PlaneSerialNo int,
EmployeeID int,
RouteNo int,
CONSTRAINT FK_PlaneSerialNo FOREIGN KEY(PlaneSerialNo)
REFERENCES Plane(PlaneSerialNo),
CONSTRAINT FK_EmployeeID FOREIGN KEY(EmployeeID)
REFERENCES Employee(EmployeeID),
CONSTRAINT FK_RouteNo FOREIGN KEY(RouteNo)
REFERENCES Route(RouteNo)
);
trying to create a sort of database system using oracle where it tracks flights but it just says the name is already used but havent seen any similarities in constraints other than identifying FKs
Oracle doesn't rely much on similarities - it has found object with exactly the same name in its dictionary and - as you can't have two objects with the same name - it raised the error.
Query user_constraints (and then user_objects, if previous search didn't find anything).
If you want to find out which table it is, you might try
select owner, table_name from dba_constraints where constraint_name = '<some value from your create table command>';
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).
I have a table and this table has relationship with itself as many-to-many. So i am create another table (second table) that stores two id for composite primary key which comes from original (first) table. But if in second table there is id1=1 and id2=2, then second table shouldn't have id1=2 and id2=1.
So how can i do that, should i write a trigger for that or is there a simple way for oracle.
I use Oracle11g and pl/sql developer.
You can try defining a unique function-based index that automatically defines the index in numerical order. This would ensure that only one of the 2 combinations is ever allowed. Something like:
create unique index your_index on your_table(
least(id1, id2),
greatest(id1, id2)
);
If it matters, there is a slight difference between this approach and MT0's answer that uses the check constraint.
With the check constraint approach, only (id1=1, id2=2) is valid.
With the function-based index approach, both (id1=1, id2=2) and (id1=2, id2=1) are valid, but they can't both be present in the table at any given time.
CREATE TABLE table_name (
id INT PRIMARY KEY
);
CREATE TABLE table_name_many_to_many(
id1 INT REFERENCES table_name( id ),
id2 INT REFERENCES table_name( id ),
CONSTRAINT tnmtm__id1__id2__pk PRIMARY KEY ( id1, id2 ),
CONSTRAINT tnmtm__id1__id2__chk CHECK ( id1 <= id2 )
);
What I have is several tables...two of them being:
CREATE TABLE Orders(
oid int NOT NULL,
rdate date,
sdate date,
cid int NOT NULL,
eid int NOT NULL,
PRIMARY KEY (oid),
FOREIGN KEY (cid) REFERENCES Customer(cid),
FOREIGN KEY (eid) REFERENCES Employee(eid));
CREATE TABLE PartOrder(
poid int NOT NULL,
pid int NOT NULL,
oid int NOT NULL,
PRIMARY KEY (poid),
FOREIGN KEY (pid) REFERENCES Part(pid),
FOREIGN KEY (oid) REFERENCES Orders(oid));
What I need to do is this:
Create and execute a query that deletes all PartOrder records for Orders for which the shipping date is in the past.
So, I came up with this...
DELETE
FROM (SELECT * FROM PartOrder FULL OUTER JOIN Orders ON partorder.oid=orders.oid)
WHERE sdate<sysdate;
This is giving me this error:
ORA-01752: cannot delete from view without exactly one key-preserved table
Can someone offer me some insight?
I'd write this as something like
DELETE FROM PARTORDER
WHERE POID IN (SELECT p.POID
FROM PARTORDER p
INNER JOIN ORDERS o
ON o.OID = p.OID
WHERE o.SDATE < SYSDATE);
Best of luck.
I've used the CREATE VIEW command to create a view (obviously), and join multiple tables. The CREATE VIEW command works perfectly, but when I try to update the VIEW RentalInfoOct, I receive error "ORA-01779: cannot modify a column which maps to a non key-preserved table"
CREATE VIEW RentalInfoOct
(branch_no, branch_name, customer_no, customer_name, item_no, rental_date)
AS
SELECT i.branchNo, b.branchName, r.customerNo, c.customerName, i.itemNo, r.dateFrom
FROM item i
INNER JOIN rental r
ON i.itemNo = r.itemNo
INNER JOIN branch b
ON i.branchNo = b.branchNo
INNER JOIN customer c
ON r.customerNo = c.customerNo
WHERE r.dateFrom
BETWEEN to_date('10-01-2009','MM-DD-YYYY')
AND to_date('10-31-2009','MM-DD-YYYY')
My update command.
UPDATE RentalInfoOct
SET item_no = '3'
WHERE customer_name = 'April Alister'
AND branch_name = 'Kingsway'
AND rental_date = '10/28/2009'
I'm not sure if this will help in solving the problem, but here are my CREATE TABLE commands
CREATE TABLE Branch
(
branchNo SMALLINT NOT NULL,
branchName VARCHAR(20) NOT NULL,
branchAddress VARCHAR(40) NOT NULL,
PRIMARY KEY (BranchNo)
);
--Item Table Definition
CREATE TABLE Item
(
branchNo SMALLINT NOT NULL,
itemNo SMALLINT NOT NULL,
itemSize VARCHAR(8) NOT NULL,
price DECIMAL(6,2) NOT NULL,
PRIMARY KEY (ItemNo, BranchNo),
FOREIGN KEY (BranchNo) REFERENCES Branch ON DELETE CASCADE,
CONSTRAINT VALIDAMT
CHECK (price > 0)
);
-- Customer Table Definition
CREATE TABLE Customer
(
customerNo SMALLINT NOT NULL,
customerName VARCHAR(15) NOT NULL,
customerAddress VARCHAR(40) NOT NULL,
customerTel VARCHAR(10),
PRIMARY KEY (CustomerNo)
);
-- Rental Table Definition
CREATE TABLE Rental
(
branchNo SMALLINT NOT NULL,
customerNo SMALLINT NOT NULL,
dateFrom DATE NOT NULL,
dateTo DATE,
itemNo SMALLINT NOT NULL,
PRIMARY KEY (BranchNo, CustomerNo, dateFrom),
FOREIGN KEY (BranchNo) REFERENCES Branch(BranchNo) ON DELETE CASCADE,
FOREIGN KEY (CustomerNo) REFERENCES Customer(CustomerNo) ON DELETE CASCADE,
CONSTRAINT CORRECTDATES CHECK (dateTo > dateFrom OR dateTo IS NULL)
);
See: Oracle: multiple table updates => ORA-01779: cannot modify a column which maps to a non key-preserved table
You're attempting to update a view with joins, but the join conditions are not based on a uniqueness constraint, which creates the possibility of multiple rows that are created from a single row in one table.
It seems like you need a Unique Key - Foreign Key relationship between the columns your join condition is based on.
EDIT: I just saw your edit. Changing r.branchNo = b.branchNo to i.branchNo = b.branchNo should go a long way. Not sure how well r.customerNo = c.customerNo will work out.