开发者

Persisting a set of Days of the Week

I'm looking for an efficient way to persist a set of Days of the Week. In other words, a user will select any number of days from a list of weekdays. The specific date doesn't matter, just t开发者_StackOverflow社区he day of the week. I need to store this set of days in a hibernate entity.

I could store one of these:

Set<DayOfWeek>
Set<Integer>

But I'm thinking it could be simpler than that. What if I just use a single int to store the data and used bitwise operations. For instance:

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

So to represent the set of Sun, Mon, Wed, Sat I would persist the integer 75. This is because 1+2+8+64 = 75.

My concern is performing queries on a field like this. Would I be able to find all entities that have Wed selected?

Does this seem like a good approach? Does anyone have a better idea?

Thanks!


You could use Enum to set up days of the week

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

Now you can use a collection of value type because of Hibernate supports it.

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

Do not forget the lifespan of a composite element or a value-type instance is bounded by the lifespan of the owning entity instance.

As said:

Would I be able to find all entities that have Wed selected ?

Yes

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

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

query.list();

Added to original answer: how do i implement FetchingStrategy

Suppose the following model

@Entity
public class Customer {

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

    // getter's and setter's

}

Now our 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;         
    }

}

Our implementation

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
    }

} 

So whether some Use Case only needs CUSTOMER, i call

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

I hope it can be useful to you

regards,


The bit approach would indeed make querying for all entities with a particular weekday difficult.

The natural way to query this in SQL or HQL would involve having a SQL function doing the decode using SQL bit operations. Or if you're using Criteria and Restrictions you could build an IN clause matching all numbers with the appropriate bit set. Neither of these is pretty...

You could alternatively map it with seven separate Boolean fields, which would make the queries easy but the Java entity code ugly.

I'd go with creating a Weekday enum and putting a Set<Weekday> in your entity, which will create an additional table, but keep the Java entity sensible and querying relatively easy. And I'd probably map that Set with eager (FetchMode.JOIN) fetching, as the set's only going to have seven elements at most.

A Map<Weekday, Boolean> is also possible, but I'd certainly skip this one!


this is how I would do it too

some people would just insert X rows or columns(one for each day) in a table for clarity

thing is, do you need speed or clarity?


I don't think this is simpler than a Set. It uses less database space, but database space is not typically expensive. It will certainly make queries more difficult, and will also make your code less human-readable.


Storing it as a set - most likely in a separate 'days' and 'userChosenDays' table - would be the most human readable, especially if you're dealing directly with the query language. It's also the most extensible.

However, SQL does provide bitwise operators, so if you're planning on dealing with the database through a web interface or something that will have checkbox-style filters anyway, it would be easy to just query bitwise against the single column and the usability wouldn't be affected.

The space and speed differences, assuming the database is properly indexed and normalized, should be negligable, and I'd recommend the storing a full set approach because maintainability is usually more important than minor performance gains.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜