This is likely a much broader SQL topic than Entity Framework, and I'm very much a newbie in both these arenas, but I'll ask it in terms of Entity Framework.
I would like to enforce a many-to-8 relationship. My setup is this:
I've tried the following:
1) Add 8 1..many associations between Person and PersonGroup. I can certainly not have more than 8 Persons per group using this solution. However, to find all groups a person is in I need to iterate over 8 variables in the Person field, which is clunky.
2) Add 8 ids to PersonGroup that match up with a Person. Once again, I can guarantee only 8 persons per group, but there is no automatic link back through the association of Person->PersonGroup. I now need to be sure to add it to two places.
3) Just do a many...many relationship and handle it in code. There are two problems with this: I cannot guarantee only 8 persons per group, and I'm unsure if I can assure the order remains the same.
So, which is the best, or what solution am I missing?
Many-to-many seems ok to me. You can easily make sure there are no more than 8 persons per group by implementing triggers. Also, you can add order column to this table if you think it's important for your logic.
An n:m
relationship with a "catch":
Person
------
PersonId
PRIMARY KEY (PersonId)
PersonGroup
-----------
GroupId
PRIMARY KEY (GroupId)
Belongs
-------
GroupId
PersonId
Ordering
PRIMARY KEY (GroupId, PersonId)
FOREIGN KEY (GroupId)
REFERENCES PersonGroup (GroupId)
FOREIGN KEY (PersonId)
REFERENCES Person (PersonId) --- all normal up to here
UNIQUE KEY (GroupId, Ordering) --- the "catch"
CONSTRAINT Ordering_chk --- ensuring only up to 8 persons
CHECK Ordering IN (1,2,3,4,5,6,7,8) --- per group
You should make sure that the CHECK
constraint is available in the SQL engine you'll use (MySQL for example would trick you into believing it has such constraints but it simply ignores them. SQL-Server does not return an error but happily adds a NULL
in the checked column if you try to insert one.)
There is a limitation to this approach. The Ordering
field has to be NOT NULL
because if it is NULL
, more than 8 rows (with NULL there) could be inserted (except for SQL-Server which would allow you only up to 9 rows, eight with values and one with NULL.)
To ensure maximum of 8 rows and NULLs in the Ordering
, you could make a more complex constraint like the one described in MSDN site, CHECK Constraints (if your RDBMS has such feature) but I'm not at all sure on the performance of such a beast:
CREATE FUNCTION CheckMax8PersonPerGroup()
RETURNS int
AS
BEGIN
DECLARE @retval int
SELECT @retval = CASE WHEN EXISTS
( SELECT *
FROM Belongs
GROUP BY GroupId
HAVING COUNT(*) > 8
)
THEN 0
ELSE 1
END
RETURN @retval
END;
GO
ALTER TABLE Belongs
ADD CONSTRAINT Ordering_chk
CHECK (CheckMax8PersonPerGroup() = 1 );
GO
The constraint could alternatively be created as a FOREIGN KEY
to a reference table with 8 rows. (If you use MySQL, that's the only way to have the equivalent of CHECK
.)
A variation would be to use the (GroupId, Ordering)
as the Primary Key and not have any constraint on the (GroupId, PersonId)
combination. This would allow for a Person
having multiple positions in a Group
(but still up to 8) .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.