问题
In Entity Framework (model-first), I'm implementing a many-many (e.g. Composition-Anthology) relationship, with an additional relation (Composer) that must match within related sets.
How can I correctly create this model in EF?
I currently have two bad ideas:
Bad Idea #1
By making the primary keys on Composition and Anthology composites, containing both ComposerId and the local Identity, EF constrains this correctly. However this causes immediate problems:
- All tables related to Composition and Anthology now also have ComposerId for FKs; painful for DBA.
- I can't use EF 5.0's EntitySet.Find() based simply on the unique Identity, etc.
Bad Idea #2
I could materialize the CompositionAnthology pivot table in the designer, adding ComposerId to it, and add a constraint directly to SQL. However this:
- Breaks EF database creation/updating
- Breaks entity navigation/addition
Note: My data actually models a much less intuitive "engagement" model, but this metaphor holds up quite well.
EDIT: I'm posting a portion of my actual model here by request, on the chance that my goals can be met with a different schematic representation. (I removed the HashSet assignments for brevity.) Logically, Composition represents Engagement in this model, because there must be a related Engagement (with matching Account) for an Endorsement to exist.
public partial class Account
{
public int Id { get; set; }
public string PrimaryEmail { get; set; }
public virtual ICollection<Endorsement> EndorsementsGiven { get; set; }
public virtual ICollection<Endorsement> EndorsementsReceived { get; set; }
public virtual ICollection<Engagement> Engagements { get; set; }
public virtual ICollection<EngagementEndorsement> EngagementEndorsements { get; set; }
}
public partial class EngagementEndorsement
{
public int Endorsement_Id { get; set; }
public int Engagement_Id { get; set; }
public int Account_Id { get; set; }
public virtual Endorsement Endorsement { get; set; }
public virtual Engagement Engagement { get; set; }
public virtual Account Account { get; set; }
}
public partial class Engagement
{
public int Id { get; set; }
public System.DateTime Start { get; set; }
public System.DateTime End { get; set; }
public string JobFunction { get; set; }
public virtual Account Account { get; set; }
public virtual ICollection<EngagementEndorsement> EngagementEndorsements { get; set; }
}
public partial class Endorsement
{
public int Id { get; set; }
public EndorsementStatus Status { get; set; }
public EndorserRole EndorserRole { get; set; }
public string Note { get; set; }
public virtual Account Endorsee { get; set; }
public virtual Account Endorser { get; set; }
public virtual ICollection<EngagementEndorsement> EngagementEndorsements { get; set; }
}
I'm currently doing "Bad Idea #2" (see above) - After the database is created, I apply the additional relations/constraints:
-- --------------------------------------------------
-- Ensure Engagement-to-Endorsement AccountId match
-- --------------------------------------------------
ALTER TABLE [dbo].[Engagements]
ADD CONSTRAINT [UK_EngagementIdAccountId]
UNIQUE NONCLUSTERED
([Id], [Account_Id])
WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
ALTER TABLE [dbo].[EngagementEndorsements]
ADD CONSTRAINT [FK_EngagementIdAccountId]
FOREIGN KEY ([Engagement_Id], [Account_Id])
REFERENCES [dbo].[Engagements]
([Id], [Account_Id])
ON DELETE NO ACTION ON UPDATE NO ACTION;
ALTER TABLE [dbo].[Endorsements]
ADD CONSTRAINT [UK_EndorsementIdAccountId]
UNIQUE NONCLUSTERED
([Id], [Endorsee_Id])
WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
ALTER TABLE [dbo].[EngagementEndorsements]
ADD CONSTRAINT [FK_EndorsementIdAccountId]
FOREIGN KEY ([Endorsement_Id], [Account_Id])
REFERENCES [dbo].[Endorsements]
([Id], [Endorsee_Id])
ON DELETE NO ACTION ON UPDATE NO ACTION;
GO
回答1:
Ultimately, based on good data schema feedback (and lack of EF feedback) in two related questions, I proceeded very much as shown in "Bad Idea #2", above.
I've been working with this and it meets all my current needs.
See these for further details on the other bits of the implementation:
- SQL constraint: https://dba.stackexchange.com/questions/41387/manymany-with-shared-relation
- EF5 navigation: Custom Entity Framework many-to-many navigation property
来源:https://stackoverflow.com/questions/16273702/model-entity-framework-many-many-plus-shared-relation