简体   繁体   中英

Entity Framework Many-To-8 Relationship?

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:

  • A PersonGroup needs 8 (unique) Persons.
  • A Person can be in many different PersonGroups.
  • The order of the PersonGroup matters (the first needs to remain first, etc).
  • Easy access to all people in a PersonGroup and all PersonGroups a Person is in.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM