Model Entity Framework many-many plus shared relation

末鹿安然 提交于 2019-12-11 09:27:30

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!