2016-03-05 5 views
0

Я использую play framework 2.3.4 с ebean. У меня есть эти 2 таблицы в моей базе данных:отрицание выражения в ebean

@Entity 
public class Device extends Model { 

    @Id 
    public Long id; 

    @OneToMany(mappedBy = "device") 
    public List<DeviceInactivePeriod> inactivePeriods = new ArrayList<DeviceInactivePeriod>(); 

    ... 
} 

@Entity 
public class DeviceInactivePeriod extends Model { 

    @Id 
    public Long id; 

    @Constraints.Required 
    @Formats.DateTime(pattern = "dd-MM-yyyy HH:mm") 
    public Date start; 

    @Formats.DateTime(pattern = "dd-MM-yyyy HH:mm") 
    public Date end; 

    @ManyToOne 
    public Device device; 

    ... 

} 

Представьте себе DeviceInactivePeriod объект как период времени, в котором устройство в неактивной. A DEVICE содержит их список.

Теперь я хочу, чтобы запросить все устройства, которые в определенный момент времени (например, сейчас) не имеет DeviceInactivePeriod (что означает, что устройство является активным)

Я пробовал много много много вещей, не работал. У меня есть этот запрос:

Date now = new Date(); 
    return 
      find.where(). 
        and(
         Expr.le("inactivePeriods.start", now), 
         Expr.ge("inactivePeriods.end", now) 
        ) 
        .orderBy(sorting + " " + order) 
        .findPagingList(Global.PAGE_SIZE_DEVICES) 
        .setFetchAhead(false) 
        .getPage(page); 

, который возвращает ровно все устройства, которые НЕАКТИВНЫ. (напротив того, что я хочу). К сожалению, отрицание этого запроса не возвращает ожидаемого результата. mayble Я отрицаю неправильно? вот что я делаю:

Date now = new Date(); 
    return 
      find.where(). 
        .not(Expr.and(
         Expr.le("inactivePeriods.start", now), 
         Expr.ge("inactivePeriods.end", now) 
        )) 
        .orderBy(sorting + " " + order) 
        .findPagingList(Global.PAGE_SIZE_DEVICES) 
        .setFetchAhead(false) 
        .getPage(page); 

Может ли кто-нибудь предложить мне решение? Или кто-нибудь может предложить исходное SQL-решение?

UPDATE

Вот сгенерированный SQL:

[debug] c.j.b.PreparedStatementHandle - select distinct t0.id c0, [...] from device t0 join device_inactive_period u1 on u1.device_id = t0.id where not ((u1.start <= 2016-03-06 11:35:15.048 and u1.end >= 2016-03-06 11:35:15.048)) order by t0.exp_date desc limit 11

Проблема заключается в том, что для каждого Device там может быть от 0 до многих строк в SQL СУБД InactiveDevicePeriod и проверяет каждую строку, если ((u1.start <= 2016-03-06 11:35:15.048 and u1.end >= 2016-03-06 11:35:15.048)) , для каждого устройства, если существует только одна строка, которая возвращает true для этого условия, все это устройство будет возвращено. Другая проблема: если устройство не имеет записи InactiveDevicePeriod, оно не возвращается.

В Java это эквивалентно этому миру кода (я думаю!) (В Device.java):

public boolean isActive_at_Wrong(Date date){ 
    for (DeviceInactivePeriod inactivePeriod : inactivePeriods) { 
     if ((inactivePeriod.start.before(date) || inactivePeriod.start.equals(date)) && inactivePeriod.end.after(date)){ 
      return false; 
     } else { 
      return true; 
     } 
    } 
    return false; 
} 

Но то, что я хочу это (в Device.java):

public boolean isAactive_at_Correct(Date date){ 
    boolean active = true; 
    for (DeviceInactivePeriod inactivePeriod : inactivePeriods) { 
     if ((inactivePeriod.start.before(date) || inactivePeriod.start.equals(date)) && inactivePeriod.end.after(date)){ 
      active = false; 
     } 
    } 

    return active; 
} 
+0

Включать сгенерированный SQL ... а потом Лоо k в предложении where и описать, что это должно быть, затем опубликуйте это с вашим вопросом. –

+0

Я только что обновил вопрос с дополнительной информацией @RobBygrave – behzad

ответ

0

Я не проверял, но я думаю, что вы можете использовать between пункт вместо:

Date now = new Date(); 
return find 
    .where() 
    .not(Expr.between("inactivePeriods.start", "inactivePeriods.end", now)) 
    .orderBy(sorting + " " + order) 
    .findPagingList(Global.PAGE_SIZE_DEVICES) 
    .setFetchAhead(false) 
    .getPage(page); 
+0

спасибо, но он по-прежнему не возвращает то, что я хочу. :-( – behzad

+0

Что возвращается в этом случае? – marcospereira

+0

У меня есть 4 образцовых устройства, 2 в настоящее время ACTIVE, а другие 2 в настоящее время НЕАКТИВНЫ. Ваш код возвращает 1 из активов и один из активных активов. Неактивный, который должен не возвращается, имеет следующие объекты DeviceInactivePeriod: 1) start: 9.2.2016 end: 1.3.2016 2) start: 3.3.2016 end: 6.3.2016 – behzad