2010-02-10 6 views
3

Я ищу эффективный способ сохранить набор дней недели. Другими словами, пользователь будет выбирать любое количество дней из списка будних дней. Конкретная дата не имеет значения, только день недели. Мне нужно сохранить этот набор дней в спящем режиме.Сохранение множества Дней недели

Я мог бы хранить один из них:

Set<DayOfWeek> 
Set<Integer> 

Но я думаю, что может быть проще, чем это. Что делать, если я просто использую один int для хранения данных и использования побитовых операций. Например:

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

Таким образом, чтобы представить набор Sun, пн, ср, сб, я бы упорствовать целое число 75. Это происходит потому, что 1 + 2 + 8 + 64 = 75.

Моя забота выполняя запросы в таком поле. Смогу ли я найти все объекты, которые выбрали Wed?

Это похоже на хороший подход? Кто-нибудь имеет лучшую идею?

Спасибо!

+0

Родственные: http://stackoverflow.com/ques/2199399/storing-enumset-in-a-database – finnw

ответ

5

Вы можете использовать Enum, чтобы установить дни недели

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

Теперь вы можете использовать коллекцию типа значения из Hibernate поддерживает его.

@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; 
} 

Не забудьте срок службы составного элемента или экземпляра значения типа ограничена продолжительностью жизни владельца экземпляра объекта.

Как сказал:

Смогу ли я найти все объекты, которые Wed выбраны?

Да

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

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

query.list(); 

Добавлена ​​оригинальный ответ: Как реализовать FetchingStrategy

Пусть следующая модель

@Entity 
public class Customer { 

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

    // getter's and setter's 

} 

Теперь наш интерфейс CustomerRepository

public interface CustomerRepository { 

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

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

} 

Наша реализация

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 
    } 

} 

Так ли какой-Use Case только потребности клиента, я называю

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); 
    } 
} 

Я надеюсь, что это может быть полезным для вас

С уважением,

+0

@Arthur - Я уже использую перечисление для будних дней, но не думал использовать CollectionOfElements. Спасибо, что напомнили об этом! Считаете ли вы целесообразным использовать следующие оптимизации аннотаций? @CollectionOfElements (fetch = FetchType.EAGER) @Enumerated (EnumType.STRING) @Column (длина = 3) @JoinTable (...). Я получал столбец varchar (255) до и теперь только varchar (3). И @donroby предлагает сделать желаемый выбор. – Tauren

+0

@Tauren Я не уверен, когда вы установите длину столбца, равную 3, это повлияет на производительность. VARCHAR означает VARIABLE CHAR, поэтому, если вы настроите STATIC CHAR, я думаю, что было бы лучше. Попробуйте вместо этого использовать @Column (columnDefinition = "CHAR (3)"). fetch = FetchType.EAGER может повлиять на производительность из-за того, что в некоторых случаях вам не нужна полностью инициализированная коллекция DAYS_OF_THE_WEEK. Было бы лучше использовать HQL, чтобы получить то, что вы действительно хотите (FetchingStrategy). –

+0

@ Артур - спасибо за совет! – Tauren

0

это, как я хотел бы сделать это слишком

некоторые люди просто вставить X строки или столбцы (по одному на каждый день) в таблице для наглядности

вещь, вам нужна скорость или ясность?

+0

Ну, я бы хотел как скорости, так и ясности! Вот почему я надеялся, что кто-то из них, возможно, предложит лучшее предложение. Но если бы мне пришлось выбирать, я думаю, что скорость может быть лучше. Это не так сложно понять, я не думаю. – Tauren

0

Я не думаю, что это проще, чем набор. Он использует меньше пространства базы данных, но пространство базы данных обычно не дорого. Это, безусловно, сделает запросы сложнее, а также сделает ваш код менее понятным для человека.

+0

Разве это не требовало бы другой таблицы и отношений? По этой причине я думал, что это будет проще. Имея еще одно отношение только для этого, кажется мне излишним. Но я вижу вашу точку зрения, это сделает ее менее понятной для человека. – Tauren

+0

Да, это потребует другой таблицы и отношений. Но я бы сказал, что это принципиально * это отношения, и притворяясь, что это не так, я, как я говорю, трудно следовать. Я всегда буду выбирать ясность по оптимизации производительности/пространства (учитывая домен, в котором я работаю). –

+0

рассмотрев ваши и другие ответы, я решил, что вы правы. Я собирался сделать преждевременную оптимизацию, которая, вероятно, никогда не понадобилась бы. Спасибо за ваш вклад. – Tauren

0

Хранение его в виде набора - скорее всего, в отдельной таблице «дни» и «userChosenDays» - будет наиболее читаемым для человека, особенно если вы напрямую работаете с языком запросов. Это также самый расширяемый.

Однако SQL действительно предоставляет побитовые операторы, поэтому, если вы планируете работать с базой данных через веб-интерфейс или что-то, что будет иметь фильтры в стиле флажка, в любом случае было бы просто просто позолотить запрос к одному столбцу и удобство использования не будет затронуто.

Разница в пространстве и скорости, если база данных правильно проиндексирована и нормализована, должна быть небрежной, и я бы рекомендовал хранить полный набор подход, поскольку ремонтопригодность обычно важнее, чем незначительная прибыль.

1

Бит-подход действительно сделает запрос для всех объектов с конкретным будним днем ​​трудным.

Естественный способ запроса этого в SQL или HQL будет включать в себя функцию SQL, выполняющую декодирование с использованием битовых операций SQL. Или, если вы используете критерии и ограничения, вы можете создать предложение IN, соответствующее всем номерам с соответствующим набором бит. Ни один из них не ...

Вы можете альтернативно отобразить его с семью отдельными булевыми полями, что упростит запросы, но код сущности Java уродливый.

Я бы пошел с созданием перечня буднего дня и помещением Set<Weekday> в вашу сущность, которая создаст дополнительную таблицу, но сохранит сущность Java и упростит запросы. И я бы, вероятно, наметил этот набор с нетерпением (FetchMode.JOIN), поскольку набор будет иметь только семь элементов.

A Map<Weekday, Boolean> также возможно, но я обязательно пропущу этот!