How to delete Category and SubCateogries? - c#

I have little Confusion that when we delete Category is it necessary to delete Subcategory related to that if so please help by writing Sql query?Similarly if delete subcategory then deleting Category will also should be deleted as well?
+-------+------------+
| CatID | CatName |
+-------+------------+
| 1 | Seeds |
| 2 | Pesticides |
| 3 | Fertilizer |
+-------+------------+
+----------+---------------+-----------+
| SubCatID | SubCatName | CatID |
+----------+---------------+-----------+
| 1 | Red Seed | 1 |
| 2 | Red Seed | 1 |
| 3 | Red Seed | 1 |
| 4 | Red Seed | 1 |
| 5 | National Worm | 2 |
+----------+---------------+-----------+

You need ON DELETE CASCADE by altering current schema :
ALTER TABLE SubCategory
ADD CONSTRAINT fk_SubCat_CatID FOREIGN KEY (CatID) REFERENCES category(CatID )
ON DELETE CASCADE;
By this when you delete category from category table, the reference data would auto delete. Just make sure drop your current constraint before create new one with ON DELETE CASCADE.

Given you have a Foreign Key defined on this relation, then yes, you have to delete (because childs cannot be orphans) or set null (if you column CatId allows null values) on the CatID column on the Subcategories table because the relational databases uses the referential integrity. You can define the CASCADE option to do it for you automatically.
ALTER TABLE SubCategory
ADD CONSTRAINT FK_SubCategory_Category
FOREIGN KEY (CatId)
REFERENCES Category (CatId)
ON DELETE CASCADE
Check this article for more details.
If you have a FK and want more control what you are deleting, you must provide two sql statements to make it, for sample.
delete from subcategory where catId = 1
delete from category where catId = 1

Related

Check child records of a record before making status of it as false in SQL Server

I have a application with some relational tables in my SQL Server database.
In the application, whenever user deletes and records I never delete it from my database, instead I make 'status' (table column) as 'False'.
Eg: User will delete a record from tblAccounts, the records has a column 'Status' which can be either true/false. On delete action record is set to false.
Now the problem is this account may be referred in other transactions. If it is used in other tables then it should not allow user to delete (make it false).
If I allow user to delete the record physically from table, it will throw foreign key error but in this scenario (making it false) how can I check the child rows without deleting and prompt the User.
I can do it by a select query on each table but that will be slow down my application.
Is there any other way/idea to achieve it?
I can do it by a select query on each table but that will be slow down
my application.
Is there any other way/idea to achieve it?
No there is not. You can do the automation with either a CHECK constraint that calls a function or with a TRIGGER, but in that code a SELECT statement against the other tables will have to be performed. There is no way around it.
You could do it using a foreign key, the trick here is to make both columns (AccountID and Status) Primary in tblAccounts. Then in the transaction table, you create a foreign key to both (AccountID and Status) with cascade on UPDATE/Delete. This means, if you ever change/delete an account id or its status from tblAccounts, the changes will be applied on all foreign keys as well.
Here is an example :
CREATE TABLE tblAccounts(
ID INT,
AccountID INT NOT NULL,
[Status] BIT NOT NULL
)
ALTER TABLE tblAccounts
ADD PRIMARY KEY (AccountID, [Status])
CREATE TABLE tblTransactions(
[ID] INT,
[TransID] INT NOT NULL PRIMARY KEY,
[AcctID] INT NOT NULL,
[Status] BIT NOT NULL
)
ALTER TABLE tblTransactions
ADD FOREIGN KEY (AcctID,[Status]) REFERENCES tblAccounts(AccountID, [Status])
ON UPDATE CASCADE
ON DELETE CASCADE
INSERT INTO tblAccounts (ID, AccountID, [Status])
VALUES
(1,1000,1),
(2,1100,1),
(3,1200,1),
(4,1300,1)
INSERT INTO tblTransactions(ID, TransID, AcctID,[Status])
VALUES
(1,5000,1000,1),
(2,3258,1300,1),
(3,5852,1000,1),
(4,9631,1100,1),
(5,1870,1200,1)
tblAccounts
| ID | AccountID | Status |
|----|-----------|--------|
| 1 | 1000 | true |
| 2 | 1100 | true |
| 3 | 1200 | true |
| 4 | 1300 | true |
tblTransactions
| ID | TransID | AcctID | Status |
|----|---------|--------|--------|
| 1 | 5000 | 1000 | true |
| 2 | 3258 | 1300 | true |
| 3 | 5852 | 1000 | true |
| 4 | 9631 | 1100 | true |
| 5 | 1870 | 1200 | true |
Let's change the status of AccountID 1100 to false
UPDATE tblAccounts
SET
[Status] = 0
WHERE
AccountID = 1100
Check tblAccount
| ID | AccountID | Status |
|----|-----------|--------|
| 1 | 1000 | true |
| 2 | 1100 | false|
| 3 | 1200 | true |
| 4 | 1300 | true |
Check tblTransactions
| ID | TransID | AcctID | Status |
|----|---------|--------|--------|
| 1 | 5000 | 1000 | true |
| 2 | 3258 | 1300 | true |
| 3 | 5852 | 1000 | true |
| 4 | 9631 | 1100 | false|
| 5 | 1870 | 1200 | true |

Creating a constraint on two columns to support specific rule

I have a table storing Device details. For simplicity, the columns are:
Id (Primary Key)
Name (varchar)
StatusId (Foreign Key to Status table).
The Status table has two columns:
Id (Primary Key)
State (varchar)
and two rows:
[Id | State]
1 | Active
2 | Inactive
I would like to allow multiple devices in the Devices table with the same Name, but only one of them can have status Active at any time.
That is to say, this should be allowed in the Devices table:
[Id | Name | StatusId]
10 | Mobile001 | 1
11 | Mobile001 | 2
12 | Mobile001 | 2
20 | Tablet001 | 1
21 | Tablet002 | 2
22 | Tablet002 | 1
23 | Tablet003 | 2
But this should not be allowed:
[Id | Name | StatusId]
10 | Mobile001 | 1 <-- wrong
11 | Mobile001 | 1 <-- wrong
12 | Mobile001 | 2
20 | Tablet001 | 1
21 | Tablet002 | 1 <-- wrong
22 | Tablet002 | 1 <-- wrong
23 | Tablet003 | 2
Is there a way how to create a constraint in T-SQL to reject inserts and updates that violate this rule? And is there a way how to do it in EF code first using EntityTypeConfigurations and Fluent API, possibly via IndexAnnotation or IndexAttributes?
Thanks.
One method, as #ZoharPeled just commented is using a filtered unique index.
As you are only allowed one Active Device of a specific name, this can be implemented as below:
USE Sandbox;
GO
--Create sample table
CREATE TABLE Device (ID int IDENTITY(1,1),
[name] varchar(10),
[StatusID] int);
--Unique Filtered Index
CREATE UNIQUE INDEX ActiveDevice ON Device ([name], [StatusID]) WHERE StatusID = 1;
GO
INSERT INTO Device ([name], StatusID)
VALUES ('Mobile1', 1); --Works
GO
INSERT INTO Device ([name], StatusID)
VALUES ('Mobile1', 0); --Works
GO
INSERT INTO Device ([name], StatusID)
VALUES ('Mobile2', 1); --Works
GO
INSERT INTO Device ([name], StatusID)
VALUES ('Mobile1', 1); --Fails
GO
UPDATE Device
SET StatusID = 1
WHERE ID = 2; --Also fails
GO
SELECT *
FROM Device;
GO
DROP TABLE Device;
Any questions, please do ask.
In EF CF You could achieve it by setting an unique index like described in this answer.
modelBuilder.Entity<Device>()
.HasIndex(d => new { d.Name, d.StatusId })
.IsUnique();

ORACLE: Use static value when defining foreign key constraint

How can I define a foreign key constraint like this in ORACLE:
ALTER TABLE TEST_STORES ADD CONSTRAINT FK_STORE_TYPE
FOREIGN KEY ("StoreTable", STORE_TYPE) REFERENCES TEST_ENUMERATIONS (TABLE, VALUE)
/
I want to combine all Enum values of several tables in one table.
In order to create a foreign key I need also to check the type of the enum since the value alone is not unique.
I need it like this so I can define the Store_Type as enum (C#) in my program but at the same time I want to make sure the database values are all valid.
For example:
TEST_STORE table:
| ID | ... | STORE_TYPE
|-----------|------------|------------
| 324234 | | 0
| 324235 | | 0
| 324236 | | 1
TEST_ENUMERATIONS table:
| ID | TABLE | VALUE | NAME
|-----------|--------------|------------|-------------
| 567234 | StoreTable | 0 | NormalStore
| 567235 | StoreTable | 1 | SpecialStore
| 567236 | AnotherTable | 0 | AnotherType
Try creating a virtual column on TEST_STORES whose value is always 'StoreTable', and use the virtual column as the first column in the foreign key.
ALTER TABLE TEST_STORES ADD (ENUM_TABLE AS 'StoreTable');
ALTER TABLE TEST_STORES ADD CONSTRAINT FK_STORE_TYPE
FOREIGN KEY (ENUM_TABLE, STORE_TYPE) REFERENCES TEST_ENUMERATIONS (TABLE, VALUE)
Seems that you need:
ALTER TABLE TEST_STORES ADD CONSTRAINT FK_STORE_TYPE
FOREIGN KEY (NAME, STORE_TYPE) REFERENCES TEST_ENUMERATIONS (TABLE, VALUE)
/
You will need a unique key on test_enumerations(table,value) as well.

Merge data from two tables from different SQL Server database in C#

I have one central and two client database that have the same structure (identity id). The application allows users to merge data of selected tables from central db with one client db at a time.
For example:
[db_central].[table]:
+-------+-------+
| id | name |
+-------+-------+
| 1 | A |
| 2 | B |
| 3 | C |
+---------------+
[db_client_1].[table]:
+-------+-------+
| id | name |
+-------+-------+
| 3 | D |
+---------------+
[db_client_2].[table]:
+-------+-------+
| id | name |
+-------+-------+
| 3 | E |
+---------------+
Expected result after merging (twice):
[db_central].[table]:
+-------+-------+
| id | name |
+-------+-------+
| 1 | A |
| 2 | B |
| 3 | C |
| 4 | D |
| 5 | E |
+---------------+
Currently, I'm only able to load tables from database.
When user clicks "Manual Sync" button, the app will compare and merge data of selected tables from left to right database or vice versa.
If table doesn't exist, it will create the new one. If table does exist, it will compare and merge data but I don't know what is the best solution to accomplish this task.
Any suggestion would be appreciated.
This seems like a simple sql query (if the databases are on the same server, or if you have a linked server between them) using except...
insert into db_central // Target table
select name from db_client_1 // Source table
except
select name from db_central // Target table
If you have to do it in Linq, then it's very similar:
// Get the list of names to add
var newNames = dbContext.db_client_1.Select(e => e.name).Except(dbContext.db_central.Select(e => e.name));
// Convert the names to a list of entity objects and add them.
dbContext.db_central.Add(newNames.Select(e => new db_central { name = e.name });
dbContext.SaveChanges();
This is assuming you don't want duplicates in db_central
Ideally you should have two columns at table in Central Database
Primary key (with identity enabled)
ChildKey (Primary Key of Child databases)
Primary key column in central database will take care of ordering, and chiild column will give you primary key in respective database

SQL Theory Multiple References

i am designing a database and have theory problem, about which solution works better to run queries, to be faster on microsoft sql server or simply more relational.
GIVEN
Lets say, we have the following Tables:
Congress, Person, Session, Room, and much more.
Don't mind about the given names. These are just some basic standalone entities.
-----------------------------------------------------------------
| Congress | Person | Session | Room |
-----------------------------------------------------------------
| CongressID | PersonID | SessionID | RoomID |
| Name | Name | Name | Name |
| ... | ... | ... | ... |
-----------------------------------------------------------------
Additionally we have a table called "Right". Rights have a name and can define access to something like one or many of the basic entities. Each person can have those rights assigned.
So there are 2 more tables:
Right and PersonRight
---------------------------------
| Right | PersonRight |
---------------------------------
| RightID | PersonRightID |
| Name | PersonID |
| ... | RightID |
| ... | ... |
---------------------------------
SOUGHT-AFTER
Now there is only one thing missing. The way or table that represents the relations to the other entities. I know three different ways that all will work, but i don't have the deep experience to decide which one will be the best.
1. The relational way?
Upgrade: For every new entity, add a new table
Relation: Right 1 : N Entities
Pros: Adding new entities doesn't affect the others in any way, foreign keys to entities
Cons: Many tables with maybe redundant columns like CreatedDate or rowguid.
SQL Example::
select *
from Right r
left join RightCongress rc on r.RightID = rc.RightID
left join RightSession rs on r.RightID = rs.RightID
left join RightRoom ro on r.RightID = ro.RightID
left join Congress ec on rc.CongressID = ec.CongressID
left join Session es on rs.SessionID = es.SessionID
left join Room er on ro.RoomID = er.RoomID
-------------------------------------------------------
| RightCongress | RightSession | RightRoom |
-------------------------------------------------------
| RightCongressID | RightSessionID | RightRoomID |
| RightID | RightID | RightID |
| CongressID | SessionID | RoomID |
| ... | ... | ... |
-------------------------------------------------------
2. The column way?
2.1 The column way 1
Upgrade: For every new entity, add a new column to table "Right"
Relation: Right 1 : 1 Entities
Pros: No new table required, small statement, foreign keys to entities
Cons: Every new entity affect all other rows, only 1:1 relation possible, column count maybe confusing
SQL Example::
select *
from Right r
left join Congress ec on r.CongressID = ec.CongressID
left join Session es on r.SessionID = es.SessionID
left join Room er on r.RoomID = er.RoomID
-----------------
| Right |
-----------------
| RightID |
| Name |
| CongressID |
| SessionID |
| RoomID |
-----------------
2.2 The column way 2
Upgrade: For every new entity, add a new column to table "RightReference"
Relation: Right 1 : N Entities
Pros: 1:N relation, only one new table, small statement, foreign keys to entities
Cons: Every new entity affect all other rows, column count maybe confusing
SQL Example::
select *
from Right r
inner join RightReference rr on r.RightID on rr.RightID
left join Congress ec on rr.CongressID = ec.CongressID
left join Session es on rr.SessionID = es.SessionID
left join Room er on rr.RoomID = er.RoomID
---------------------------------------
| Right | RightReference |
---------------------------------------
| RightID | RightReferenceID |
| Name | RightID |
| ... | CongressID |
| ... | SessionID |
| ... | RoomID |
| ... | ... |
---------------------------------------
3. The reference way
Upgrade: For every new entity, add a new row to RightReference with the new ReferenceTypeID
Relation: Right 1 : N Entities
Pros: Only one new table and dynamic references
Cons: Anonymous references and have always to remember the indexes to build queries, no foreign keys to entities
Explanation: ReferenceID is the primary ID of the referenced entity/row, like of table Congress, Session and so on. So you can't suggest to which table it references. For that reason there is ReferenceTypeID. It points to a translation table called ReferenceType, where every table is stored with an unique id. Maybe it is possible to use the system method OBJECT_ID instead.
SQL Example::
select *
from Right r
inner join RightReference rr on r.RightID = rr.RightID
left join Congress ec on rr.ReferenceID = CongressID and rr.ReferenceType = 1
left join Session es on rr.ReferenceID = SessionID and rr.ReferenceType = 2
left join Room er on rr.ReferenceID = RoomID and rr.ReferenceType = 3
----------------------------------------------------------
| Right | RightReference | ReferenceType |
----------------------------------------------------------
| RightID | RightReferenceID | ReferenceTypeID |
| Name | RightID | Name |
| ... | ReferenceID | ... |
| ... | ReferenceTypeID | ... |
| ... | ... | ... |
----------------------------------------------------------
And now to all the sql experts.
What is the best or better lets say state of the art solution/way/approach to handle this task?
If you have other ways, please let me know.
What i am Looking for is: General Advantages and Disadavantages, SQL-Performance, implementation difficulties with EntityFramework and everything else you know or think about it.
Thanks!
Usually when dealing with relational databases, anything that requires a schema change is a no-no because you have to do potentially dangerous operations on your SQL server, update EF as well as whatever models you may be using and probably redeploy whatever application serves as the frontend for your database.
The SQL Solution
If you're OK with committing a no-no every time a new entity is added or are for some other reason tied to an RDBMS, you have two options:
If you care about your entity(Congress, Session, Room) table schema
Column way #2 is probably the best idea because it separates relational data from actual table data. Make a separate table for the relationships between entities and rights and put an index on every possible entityId. In your example you'd need indices on CongressId, SessionId and RoomId columns.
If you don't care about your entity table schema
Combine all entity tables into one large Entities table with an Id column and an XML column that contains all your actual entity info such as the type. Single relationship between Entities and rights and you're good.
The NoSQL Solution
If you can go this route, it would probably suit the flexible structure you're looking for much better. You will still need to update the code that accesses the document store but judging from your proposal that seems unavoidable unless you have some extraordinarily-flexible-but-error-prone code in place.
You don't need to do schema/EF updates every time a new entity type is added, and you don't need to worry about relationships. Your Person objects will have all their rights nested right inside and will be stored in the document store exactly that way.

Categories

Resources