2009-03-27 12 views
5

Se ho tre entità, Project, ProjectRole e Person, dove una persona può essere un membro di diversi progetti ed essere in diversi ruoli di progetto (come "Project Lead" o "Project Member") - come modellizzerete un rapporto?Come modelli i ruoli/le relazioni con Domain Driven Design in mente?

Nel database, al momento sono presenti i seguenti tablers: Progetto, Persona, ProjectRole Project_Person con PersonId & ProjectId come PK e ProjectRoleId come relazione FK.

Sono davvero in perdita qui poiché tutti i modelli di dominio che ho trovato sembrano rompere qualche regola "DDD". Ci sono degli "standard" per questo problema?

Ho dato un'occhiata a una modellazione semplificata degli oggetti e c'è un esempio di aspetto di Project e ProjectMember, ma AddProjectMember() in Project chiamerebbe ProjectMember.AddProject(). Quindi Project ha un elenco di ProjectMembers e ogni ProjectMember in cambio ha un riferimento al progetto. Sembra un po 'contorto per me.

aggiornamento

Dopo aver letto di più su questo argomento, cercherò il seguente: Ci sono ruoli distinti, o meglio, i rapporti del modello, che sono di un certo tipo ruolo nel mio dominio. Ad esempio, ProjectMember è un ruolo distinto che ci dice qualcosa sulla relazione che una persona gioca all'interno di un progetto. Contiene un ProjectMembershipType che ci dice di più sul ruolo che svolgerà. So per certo che le persone dovranno svolgere ruoli all'interno di un progetto, quindi modellerò quella relazione.

ProjectMembershipTypes può essere creato e modificato. Questi possono essere "Project Leader", "Developer", "External Adviser" o qualcosa di diverso.

Una persona può avere molti ruoli all'interno di un progetto e questi ruoli possono iniziare e terminare in una certa data. Tali relazioni sono modellate dalla classe ProjectMember.

public class ProjectMember : IRole 
{ 
    public virtual int ProjectMemberId { get; set; } 
    public virtual ProjectMembershipType ProjectMembershipType { get; set; } 

    public virtual Person Person { get; set; } 
    public virtual Project Project { get; set; } 
    public virtual DateTime From { get; set; } 
    public virtual DateTime Thru { get; set; } 
    // etc... 
} 

ProjectMembershipType: ie. "Project Manager", "Sviluppatore", "consigliere"

public class ProjectMembershipType : IRoleType 
{ 
    public virtual int ProjectMembershipTypeId { get; set; } 
    public virtual string Name { get; set; } 
    public virtual string Description { get; set; } 

    // etc... 
} 

risposta

1

Stai modellando una relazione molti-a-molti: un progetto può avere molte persone che lavorano su di esso e una persona può lavorare su più progetti.

Si sta modellando la relazione come un ruolo di progetto, che oltre a servire come collegamento bidirezionale da Persona < -> Progetto, registra anche un RoleType e l'inizio/fine di quella persona che riempie quel RoleType su quel Progetto . (Notate come funziona l'inglese "that" per il database FK o, in codice, un puntatore/riferimento?)

A causa di questi FK, possiamo nel database seguire il grafico da Persona, tramite Ruolo del progetto, al progetto:

select a.person_id, b.project_role_id, c.project_id 
from person a join project_role b on (a.id = b.person_id) 
join project c on (b.project_id = c.id) 
where a.person_id = ? 

Oppure possiamo seguirla nella direzione opposta, da Project:

select a.person_id, b.project_role_id, c.project_id 
from person a join project_role b on (a.id = b.person_id) 
join project c on (b.project_id = c.id) 
where c.project_id = ? 

Idealmente, vorremmo essere in grado di fare lo stesso nel codice C#. Quindi sì, vogliamo che una persona abbia una lista e Project abbia una lista e riferimenti a ProjectRole a una persona e a un progetto.

Sì, Project::addPerson(Person&) dovrebbe davvero essere Project::addProjectRole(ProjectRole&), a meno che non decidiamo che Project::addPerson(Person&) è un metodo comodo della forma:

void Project::addPerson(Person& p) { 
    this.addProjectRole(new ProjectRole(p, &this, RoleType::UNASSIGNED) ; 
} 

Un ProjectRole non ha una lista, ha-un riferimento a una persona e un riferimento a un progetto. Ha anche, come valori, una data di inizio, una data di fine e un RoleType (che o è un enum, o un'istanza di classe che imita un valore enum - cioè, c'è un solo oggetto per tipo enum, ed è apolidi, immutabili e idempotenti, e quindi condivisibili tra molti ProjectRoles).

Ora, questo non deve significare che il recupero di una Persona dal database dovrebbe causare l'intero database da reificata nel grafico oggetto nel codice; i proxy pigri che recuperano solo in uso possono salvarci da questo. Quindi se ci occupiamo solo della Persona, e non dei suoi Ruoli (e Progetti, possiamo semplicemente recuperare la Persona. (NHibernate, per esempio, penso che funzioni più o meno senza problemi.)

Fondamentalmente , penso che:

1) si tratta di un modo standard di rappresentare molti-a-molti rapporti; 2) È standard per una relazione avere dati aggiuntivi (quando, che tipo di) e; 3) hai praticamente avuto l'idea giusta e stai semplicemente giustamente coscienzioso nel ricevere feedback qui.

0

non sei confondere il "Descrizione" di un ruolo con il ruolo che una persona ha in un progetto? Aggiungendo il concetto "RoleDescription" (una "classe di ruolo" per intenderci) e gli oggetti "RoleInstance" che si riferiscono a persone reali nei progetti possono aiutare.

+0

Non ho idea, è possibile, non sono sicuro di cosa intendi – kitsune

+0

Ho paura di uscire dall'era del database relazionale ma ho mangiato troppo OOD ... Mi riferisco alla "seconda soluzione" in La risposta di Jamie. – xtofl

0

Quello che hai è una relazione molti-a-molti con dati aggiuntivi, il ruolo. Abbiamo una struttura simile, tranne nel caso in cui una persona possa avere più ruoli in un progetto, quindi ho faticato con le stesse domande. Una soluzione è quella di creare una classe che si estende ProjectPerson persona e aggiunge la proprietà ruolo:

public class ProjectPerson : Person 
{ 
    public string Role { get; set; } 
} 

La classe del progetto ora ha una collezione di ProjectPerson ma la classe Person ha una collezione di progetto, perché non ha senso estendi la classe Project per aggiungere un ruolo. Dovrai eseguire un lavoro aggiuntivo (cercare la persona nella raccolta ProjectPerson) per trovare il ruolo su un progetto dal punto di vista della persona.

Una seconda soluzione è il modo standard per gestire relazioni molti-a-molti con dati aggiuntivi. Creare una classe ProjectRole e modellarla come il lato multiplo di due relazioni uno-a-molti da Progetto e Persona. Cioè, sia Project che Person hanno ciascuno una collezione di ProjectRole.

È importante considerare quanto bene la strategia di accesso ai dati supporterà il modello nella scelta di una soluzione. Si desidera evitare scenari in cui il caricamento della raccolta richiede uno o più viaggi nel database per ciascun oggetto nella raccolta.

+0

Vorrei sconsigliare la classe 'ProjectPerson', perché prima o poi finirai con un 'BillablePerson', un 'InternshipPerson' e un 'TerriblePerson', tutti riferiti alla stessa persona 'reale'. Mi sono attenuto alle relazioni has-a invece che alla soluzione dell'eredità. – xtofl

+0

Non capisco il tuo argomento: in che modo la soluzione proposta potrebbe creare estensioni aggiuntive di Person? Un ProjectPerson è solo una persona in un ruolo nel contesto di un progetto. Nei termini del database viene recuperato unendo la tabella delle persone alla tabella dei collegamenti molti-a-molti. –

3

Ecco come vorrei gestirlo:

class Person 
{ 
    string Name { get; set; } 
    IList<Role> Roles { get; private set; } 
} 

class Role 
{ 
    string Name { get; set; } 
    string Description { get; set; } 
    IList<Person> Members { get; private set; } 
} 

class Project 
{ 
    string Name { get; set; } 
    string Description { get; set; } 
    IList<ProjectMember> Members { get; private set; } 
} 

class ProjectMember 
{ 
    Project Project { get; private set; } 
    Person Person { get; set; } 
    Role Role { get; set; } 
} 

Il ProjectMember classe li riunisce tutti. Questo modello ti offre la flessibilità di assegnare la stessa persona a diversi progetti con diversi ruoli (ad esempio, potrebbe essere uno sviluppatore su ProjectA e un tester su ProjectB).

Si prega di non creare classi di ruolo specifiche - quella lezione è già stata appreso.

ho creato un sample app per dimostrare questo (che comprende i rapporti troppo):

  1. Run "bin \ debug \ RolesRelationshipsSample.exe"
  2. doppio clic sulle icone della biblioteca per creare entità
  3. drag/rilasciarli per assegnare le relazioni appropriate

Sentitevi liberi di giocare con il codice. Spero che tu lo trovi utile

+0

Grazie! Sono andato in una direzione simile come la tua, per favore controlla la mia domanda aggiornata. – kitsune

+0

@Vijay Patel Perché non creare classi di ruolo specifiche? Cosa succede se ogni ruolo può eseguire diverse azioni nel progetto? – richard

+0

@Richard: dal mio esempio, la sottoclassificazione da "Ruolo" non è un problema. Penso che stavo alludendo di più allo scenario di Jamie Ide sotto http://stackoverflow.com/a/689618/80369 –

0

Sembra che ci siano due entità principali: Project e Project Member. Il membro del progetto ha gli attributi "Ruolo membro" e "Nome membro". Ciascuno di questi attributi può appartenere a un dominio, ovvero un insieme di valori che può essere mantenuto nelle tabelle di ricerca sia per comodità che per la ricerca. Si presume che qualcuno richieda informazioni su tutti i membri del progetto che svolgono un particolare ruolo/lavoro.

Nota. Le tabelle di ricerca possono avere voci aggiunte ma normalmente non hanno il valore di una voce modificata. Una volta che un valore viene selezionato dalla tabella di ricerca, viene considerato un dispositivo permanente della tabella proprietaria, in questo caso la tabella Membro del progetto.

non mi aspetto di vedere un'entità 'persona' o un tavolo in qualsiasi attività diversa dalla convenienza come una tabella di ricerca, come nel caso precedente. I dipartimenti delle risorse umane terranno un elenco di dipendenti che hanno informazioni specifiche richieste dal libro paga, ecc. Ma non c'è nulla di fondamentale per le persone che l'azienda dovrà conoscere. NB Individuare il processo aziendale per identificare un'entità - non inventare.

Problemi correlati