Ho lottato con un progetto quindi ho pensato di chiedere qui e vedere se qualcuno è in grado di aiutarti :)
Panoramica di alto livello
Sto progettando un'applicazione per gamify l'esercizio creando mini competizioni (ad esempio, chi può perdere più peso in 3 mesi o andare in bicicletta più miglia in un mese).
Gli utenti possono creare gare (chiamandole per ora gare) e devono essere in grado di specificare i vincoli - i partecipanti devono essere in una certa fascia di età, oltre un certo peso, il numero massimo di partecipanti in una gara, ecc.
I miei oggetti
RaceParticipant: per brevità, l'unica proprietà pertinente è int Age.
Race:
public class Race
{
public virtual int RaceId { get; set; }
public virtual string RaceName { get; set; }
public virtual int RaceTypeId { get; set; }
public virtual TrainingType RaceType { get; set; }
public virtual IEnumerable<RaceParticipant> RaceParticipants { get; set; }
public virtual IEnumerable<RaceConstraint> RaceConstraints { get; set; }
}
Classe astratta RaceConstraint:
public abstract class RaceConstraint
{
public string DisplayText { get; set; }
public string ValidationText { get; set; }
public virtual bool PassesConstraint(Race race, RaceParticipant participant);
}
Implementazione RaceConstraint MaxNumberOfParticipants:
public class MaxNumberOfParticipants : RaceConstraint
{
public int MaximumNumberOfParticipants { get; set; }
public MaxNumberOfParticipants()
{
DisplayText = "Maximum number of racers";
ValidationText = "This race has reached the maximum number of racers.";
}
public override bool PassesConstraint(Race race, RaceParticipant participant)
{
bool result = false;
if (race.RaceParticipants.Count() <= MaximumNumberOfParticipants)
{
result = true;
}
return result;
}
}
Implementazione RaceConstraint AgeRange:
public class AgeRange : RaceConstraint
{
public int MinimumAge { get; set; }
public int MaximumAge { get; set; }
public AgeRange()
{
DisplayText = "Age range of racers";
ValidationText = string.Format("Racers must be between the ages of {0} and {1}.", MinimumAge, MaximumAge);
}
public override bool PassesConstraint(Race race, RaceParticipant participant)
{
bool result = false;
if (MinimumAge <= participant.Age && participant.Age <= MaximumAge)
{
result = true;
}
return result;
}
}
La domanda
La mia domanda è dove memorizzare MinimumAge, MaximumAge e MaximumNumberOfParticipants. Sto utilizzando il codice Entity Framework in primo luogo, quindi so che non devo preoccuparmi dello schema direttamente, ma devo riflettere su quali proprietà aggiungere a EF e su quale oggetto saranno connesse.
Attualmente EF creerebbe una tabella separata per ogni implementazione di RaceConstraint che sembra eccessivo e sicuramente non voglio che DisplayText e ValidationText siano memorizzati nel db per ogni istanza.
Ho pensato di spostare MinimumAge, MaximumAge e MaximumNumberOfParticipants su proprietà di Race perché ogni razza avrà valori per questi, ma sembra che Race e RaceConstraint siano troppo accoppiati. Mi piacerebbe poter aggiungere un RaceConstraint in futuro quando i requisiti cambiano senza dover aggiungere una proprietà a Race e quindi aggiungere una colonna alla tabella db Race.
Penso che dovrò creare un oggetto contenitore per RaceConstraint che contiene una raccolta di tutti i RaceConstraints possibili. Avrebbe senso inserire queste proprietà in quell'oggetto e quindi rimuovere IEnumerable RaceConstraints da Race e aggiungere invece una proprietà per RaceConstraintContainer?
O forse ci sto pensando troppo e c'è un modello di progettazione che posso seguire. Sono sicuro di non essere la prima persona ad imbattersi in questo scenario!
Grazie in anticipo.
Aggiorna
Dopo averlo rimuginato per alcuni giorni e aver provato ognuna delle risposte, penso che @maple_shaft abbia davvero inchiodato il problema di EF che ostacola la progettazione di OO. Penso di aver trovato un compromesso da qualche parte nel mezzo. Ho aggiunto proprietà come MinimumAge, MaximumAge e MaximumNumberOfParticipants all'oggetto Race perché dal punto di vista del database, queste sono tutte molto correlate e ogni gara avrà voci per ognuna di queste.
Ho modificato la classe astratta RaceConstraint in un'interfaccia che richiede solo il passaggio di PassesConstraint (). Ho fatto un uso migliore di DisplayText facendone un'annotazione dei dati delle proprietà in gara (es. [Visualizza (Nome="Numero massimo di corridori")]) poiché in realtà l'ho voluto solo per le etichette nell'interfaccia utente. Ho spostato il testo da ValidationText a un messaggio di eccezione se un PassesConstraint () ha esito negativo.
Infine, ho creato una classe RaceManager per tenere un elenco di RaceConstraints e gestire l'aggiunta di utenti controllando ogni RaceConstraint. Questa classe gestirà anche la rimozione degli utenti, la determinazione dei vincitori, ecc.
Penso che funzionerà bene anche da un punto di vista MVC perché non sto passando i modelli alla vista che hanno metodi. La classe Race sarà davvero lì solo per contenere i dati EF e renderà un modello pulito da utilizzare per aggiungere o aggiornare gare da una vista.
Grazie per l'aiuto a tutti!