2010-02-10 5 views
3

Je cherche un moyen efficace de persister une série de jours de la semaine. En d'autres termes, un utilisateur sélectionnera n'importe quel nombre de jours parmi une liste de jours de la semaine. La date précise n'a pas d'importance, juste le jour de la semaine. J'ai besoin de stocker cet ensemble de jours dans une entité mise en veille prolongée.Persévérer une série de jours de la semaine

je pouvais stocker un de ces:

Set<DayOfWeek> 
Set<Integer> 

Mais je pense qu'il pourrait être plus simple que cela. Que se passe-t-il si je n'utilise qu'un seul int pour stocker les données et utilisé les opérations au niveau du bit. Par exemple:

Sun = 1 
Mon = 2 
Tue = 4 
Wed = 8 
Thu = 16 
Fri = 32 
Sat = 64 

Donc, pour représenter l'ensemble de Sun, lun, mer, Sam je persisteraient l'entier 75. En effet, 1 + 2 + 8 + 64 = 75.

Ma préoccupation est effectuer des requêtes sur un champ comme celui-ci. Serais-je capable de trouver toutes les entités qui ont été sélectionnées?

Est-ce que cela semble être une bonne approche? Quelqu'un a-t-il une meilleure idée?

Merci!

+0

Connexe: http://stackoverflow.com/questions/2 199399/stockage-enumset-dans-une-base de données – finnw

Répondre

5

Vous pouvez utiliser Enum pour mettre en place les jours de la semaine

public enum DAYS_OF_THE_WEEK { 
    SUN, 
    MON, 
    TUE, 
    WED, 
    THU, 
    FRI, 
    SAT; 
} 

Maintenant, vous pouvez utiliser une collection de type valeur en raison de Hibernate supporte.

@CollectionOfElements 
@Enumerated(EnumType.STRING) 
@JoinTable(
    name="SELECTED_DAYS_OF_THE_WEEK", 
    [email protected](name="<OWNING_ENTITY_ID_GOES_HERE>") 
) 
public Set<DAYS_OF_THE_WEEK> getSelectedDays() { 
    return this.selectedDays; 
} 

Ne pas oublier la durée de vie d'un élément composite ou une instance de type valeur est limitée par la durée de vie de l'occurrence de l'entité propriétaire.

Comme l'a dit:

Serais-je en mesure de trouver toutes les entités qui ont Mer sélectionnés?

Oui

select distinc OwningEntity _owningEntity inner join fetch _owningEntity.selectedDays selectedDay where selectedDay = :selectedDay 

query.setParameter("selectedDay", DAYS_OF_THE_WEEK.WED); 

query.list(); 

Ajouté à la réponse originale: comment puis-je mettre FetchingStrategy

Supposons que le modèle suivant

@Entity 
public class Customer { 

    private List<Order> orderList = new ArrayList<Order>(); 

    // getter's and setter's 

} 

Maintenant notre interface CustomerRepository

public interface CustomerRepository { 

    Customer getById(Integer id, CustomerFetchingStrategy fetchingStrategy); 
    List<Customer> getAll(CustomerFetchingStrategy fetchingStrategy); 

    public static enum CustomerFetchingStrategy { 
     PROXY, 
     CUSTOMER, 
     CUSTOMER_WITH_ORDERS;   
    } 

} 

Notre implémentation

import static br.com.app.CustomerRepository.CustomerFetchingStrategy; 

public class CustomerRepositoryImpl implements CustomerRepository { 

    // Usually Spring IoC or Seam @In-jection or something else 
    private SessionFactory sessionFactory; 

    public Customer getById(Integer id, CustomerFetchingStrategy fetchingStrategy) { 
     switch(fetchingStrategy) { 
      case PROXY: 
       return (Customer) sessionFactory.getCurrentSession().load(Customer.class, id); 
      case CUSTOMER: 
       return (Customer) sessionFactory.getCurrentSession().get(Customer.class, id); 
      case CUSTOMER_WITH_ORDERS: 
       return (Customer) sessionFactory.getCurrentSession().createQuery("from Customer c left join fetch c.orderList where c.id = :id") 
            .setParameter("id", id) 
            .list().get(0); 
     } 
    } 

    public List<Customer> getAll(CustomerFetchingStrategy fetchingStrategy) { 
     // Same strategy as shown above 
    } 

} 

Alors que certains cas d'utilisation seulement besoins des clients, j'appelle

import static br.com.app.CustomerRepository.CustomerFetchingStrategy; 

public class SomeController { 

    // Again Spring Ioc or Seam @In-jection 
    private CustomerRepository customerRepository; 

    public void proccessForm(HttpServletRequest request, HttpServletResponse response) { 
     request.setParameter("customer", customerRepository.getById(Integer.valueOf(request.getParameter("customerId"))), CUSTOMER); 
    } 
} 

J'espère qu'il peut être utile pour vous

Cordialement,

+0

@Arthur - J'utilise déjà une énumération pour les jours de la semaine, mais je n'avais pas pensé à utiliser CollectionOfElements. Merci de nous le rappeler! Pensez-vous qu'il est logique d'utiliser les optimisations d'annotation suivantes? @CollectionOfElements (fetch = FetchType.EAGER) @Enumerated (EnumType.STRING) @Column (length = 3) @JoinTable (...). Je recevais une colonne de varchar (255) avant et maintenant juste varchar (3). Et @donroby suggère de faire un fetch impatient. – Tauren

+0

@Tauren Je ne suis pas sûr que lorsque vous définissez votre longueur de colonne égale à 3, cela affectera les performances. VARCHAR signifie CHAR VARIABLE, donc si vous configurez un CHAR STATIQUE, je pense qu'il serait préférable de le faire. Essayez d'utiliser @Column (columnDefinition = "CHAR (3)") à la place. fetch = FetchType.EAGER peut avoir un impact sur les performances car, à certains moments, vous ne voulez pas d'une collection entièrement initialisée de DAYS_OF_THE_WEEK. Il vaudrait mieux utiliser HQL pour récupérer ce que vous voulez vraiment (FetchingStrategy). –

+0

@Arthur - merci pour le conseil! – Tauren

0

Voilà comment je le ferais aussi

certaines personnes simplement d'insérer des lignes de X ou de colonnes (une pour chaque jour) dans un tableau pour plus de clarté

chose est, vous avez besoin de vitesse ou de clarté?

+0

Eh bien, je voudrais à la fois la vitesse et la clarté! C'est pourquoi j'espérais que quelqu'un sur SO pourrait avoir une meilleure suggestion. Mais si je devais choisir, je pense que la vitesse pourrait être meilleure. Ce ne sera pas si difficile à comprendre que je ne pense pas. – Tauren

0

Je ne pense pas que ce soit plus simple qu'un ensemble. Il utilise moins d'espace de base de données, mais l'espace de base de données n'est généralement pas cher. Cela rendra certainement les requêtes plus difficiles et rendra votre code moins lisible.

+0

Cela ne nécessiterait-il pas une autre table et une relation? Pour cette raison, je pensais que ce serait plus simple. Ayant une autre relation juste pour cela semble être trop pour moi. Mais je vois votre point de vue, cela le rendrait moins lisible par l'homme. – Tauren

+0

Oui, cela nécessiterait une autre table et une autre relation. Mais je dirais que c'est fondamentalement * une * relation, et prétendre que ce n'est pas, comme je le dis, le rend difficile à suivre. Je choisirai toujours la clarté plutôt que l'optimisation des performances/de l'espace (étant donné le domaine dans lequel je travaille). –

+0

après avoir examiné votre réponse et d'autres, j'ai décidé que vous avez raison. J'allais pour une optimisation prématurée qui n'aurait probablement jamais été nécessaire de toute façon. Merci pour votre contribution. – Tauren

0

Le stocker en tant qu'ensemble - très probablement dans une table séparée 'days' et 'userChosenDays' - serait le plus lisible par l'homme, surtout si vous traitez directement avec le langage de requête. C'est aussi le plus extensible. Cependant, SQL fournit des opérateurs au niveau du bit, donc si vous envisagez de traiter la base de données via une interface web ou quelque chose qui aura des filtres de style checkbox, il serait facile de juste interroger bit à bit par rapport à la colonne et l'utilisabilité ne serait pas affectée. Les différences d'espace et de vitesse, en supposant que la base de données est correctement indexée et normalisée, devraient être négligeables, et je recommande de stocker une approche de jeu complet parce que la maintenabilité est généralement plus importante que les gains de performance mineurs.

1

L'approche binaire rendrait en effet difficile l'interrogation de toutes les entités avec un jour de la semaine particulier.

La manière naturelle d'interroger cela en SQL ou HQL impliquerait qu'une fonction SQL effectue le décodage en utilisant des opérations de bits SQL. Ou si vous utilisez des critères et des restrictions, vous pouvez créer une clause IN correspondant à tous les nombres avec l'ensemble de bits approprié. Ni l'un ni l'autre de ces ...

Vous pouvez également le mapper avec sept champs booléens distincts, ce qui rendrait les requêtes plus faciles, mais le code d'entité Java serait moche.

Je voudrais créer une énumération en semaine et mettre un Set<Weekday> dans votre entité, ce qui créera une table supplémentaire, mais gardera l'entité Java sensible et l'interrogation relativement facile. Et je le mapperais probablement avec impatience (FetchMode.JOIN) aller chercher, car l'ensemble ne va avoir que sept éléments au maximum. Un Map<Weekday, Boolean> est également possible, mais je passerais certainement celui-ci!

Questions connexes