0

Play 2.0とEbeanを使用してWebアプリの1つを再作成しようとしていますが、障害が発生しました。SETMySQLのタイプをモデルのフィールドにマップする方法がわかりません。ENUMアノテーションを使用して列を機能させましたが、列@Enumerated(EnumType.STRING)に関する情報が見つからないようですSET

このテーブルはcrontabを模倣しています。

CREATE TABLE IF NOT EXISTS `schedule` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `task_id` mediumint(8) unsigned NOT NULL default '0',
  `month` set('January','February','March','April','May','June','July','August','September','October','November','December') default NULL,
  `mday` set('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31','-1','-2','-3','-4','-5','-6','-7','-8','-9','-10') default NULL,
  `wday` set('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday') default NULL,
  `hour` set('0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23') default NULL,
  `minute` set('00','01','02','03','04','05','06','07','08','09','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31','32','33','34','35','36','37','38','39','40','41','42','43','44','45','46','47','48','49','50','51','52','53','54','55','56','57','58','59') default NULL,
  `updated` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
  PRIMARY KEY  (`id`),
  KEY `event` (`task_id`)
)

MvGによって提案されたように、UserTypeと関連するアノテーションを作成しました。

@Entity
public class Schedule extends Model {

    public enum Month { JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER };
    public enum Weekday { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY };

    @Id
    public Long id;

    @ManyToOne(cascade = CascadeType.MERGE)
    public Task task;
    @Version
    public Timestamp updated;

    @Type(type="models.EnumSetUserType",parameters=@Parameter(name="enumType",value="models.Schedule$Month"))
    @Column(name="month", columnDefinition="SET('JANUARY','FEBRUARY','MARCH','APRIL','MAY','JUNE','JULY','AUGUST','SEPTEMBER','OCTOBER','NOVEMBER','DECEMBER')")
    @MonthEnum
    public EnumSet<Month> months;

    @Type(type="models.IntegerSetUserType")
    @IntegerSet(min=-30,max=30)
    @Column(name="mday",columnDefinition="SET('1','2','3','4','5','6','7','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31','-1','-2','-3','-4','-5','-6','-7','-8','-9')")
    public Set<Integer> mdays;

    @Type(type="models.EnumSetUserType", parameters = @Parameter(name="enumType", value="models.Schedule$Weekday"))
    @Column(name="wday", columnDefinition="SET('MONDAY','TUESDAY','WEDNESDAY','THURSDAY','FRIDAY','SATURDAY')")
    @WeekdayEnum
    public EnumSet<Weekday> weekdays;

    @Type(type="models.IntegerSetUserType")
    @IntegerSet(min=0,max=23)
    @Column(name="hour",columnDefinition="SET('0','1','2','3','4','5','6','7','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23')")
    public Set<Integer> hours;

    @Type(type="models.IntegerSetUserType")
    @IntegerSet(min=0,max=59)
    @Column(name="minute",columnDefinition="SET('00','01','02','03','04','05','06','07','08','09','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31','32','33','34','35','36','37','38','39','40','41','42','43','44','45','46','47','48','49','50','51','52','53','54','55','56','57','58','59')")
    public Set<Integer> minutes;

    public static Finder<Long,Schedule> find = new Finder<Long,Schedule>(Long.class, Schedule.class);

}

EnumSetUserType

public class EnumSetUserType<E extends Enum<E>> implements UserType, ParameterizedType, Serializable {
    private Class<? extends EnumSet> clazz = null;
    private Class<E> enum_type = null;

    @Override
    public void setParameterValues(Properties parameters) {
        String enum_class_name = parameters.getProperty("enumType");
        try {
            enum_type = ReflectHelper.classForName(parameters.getProperty("enumType"), this.getClass()).asSubclass(Enum.class);
            //enum_type = (Class<E>) Class.forName(enum_class_name);
            //enum_type = (Class<E>) Play.application().classloader().loadClass(enum_class_name);
        }
        catch (ClassNotFoundException e) {
            throw new HibernateException("enum class " + enum_class_name + " not found", e);
        }
    }

    @Override
    public Object nullSafeGet(ResultSet rs, String[] column_names, SessionImplementor session, Object owner) throws HibernateException, SQLException {
        String value_str = rs.getString(column_names[0]);
        System.out.println("getting " + column_names[0] + " using " + getClass());
        if (rs.wasNull())
            return null;

        List<E> enum_values = new ArrayList<E>();
        for (String value : value_str.split(","))
            enum_values.add(Enum.valueOf(enum_type, value));

        return EnumSet.copyOf(enum_values);
    }

    @Override
    public void nullSafeSet(PreparedStatement statement, Object object, int index, SessionImplementor session) throws HibernateException, SQLException {
        System.out.println("Setting " + index + " to " + object + " using " + getClass());
        if (object == null) {
            statement.setNull(index, Types.VARCHAR);
            return;
        }

        Set<E> values = (Set<E>) object;
        StringBuilder sb = new StringBuilder();
        for (E value : values)
            sb.append(value.name()).append(",");

        System.out.println("Setting " + index + " to " + sb.length() + " using " + getClass());
        statement.setString(index, sb.substring(0, sb.length() - 1));
    }

    @Override
    public int[] sqlTypes() {
        return new int[] { Types.VARCHAR };
    }

    @Override
    public Class returnedClass() {
        return clazz;
    }

    @Override
    public Object deepCopy(Object value) throws HibernateException {
        return value;
    }

    @Override
    public boolean isMutable() {
        return false;
    }

    @Override
    public Object replace(Object original, Object target, Object owner) throws HibernateException {
        return original;
    }

    @Override
    public Object assemble(Serializable cached, Object owner) throws HibernateException {
        return cached;
    }

    @Override
    public Serializable disassemble(Object value) throws HibernateException {
        return (Serializable) value;
    }

    @Override
    public boolean equals(Object x, Object y) throws HibernateException {
        if (x == y)
            return true;

        if (x == null || y == null)
            return false;

        return x.equals(y);
    }

    @Override
    public int hashCode(Object x) throws HibernateException {
        return x.hashCode();
    }

}

エラーは報告されなくなりましたScheduleが、コントローラーアクションに手動でデータを入力して保存しても、Setフィールドはデータベースに保存されません。Play + Ebeanをこのテーブルで動作させるにはどうすればよいですか?

4

1 に答える 1

0

列を Java Enumeration にマップする場合ENUMは、おそらくSET列を Java にマップする必要がありますEnumSet。マッピングに関する SF に関する質問が少なくとも1 つEnumSetありますが、解決策は mysqlSETタイプではなく別のテーブルにあるようです。

また、hybernate では mysqlSETタイプがサポートされていないようです。したがって、独自に記述する必要がありますUserType。違いについてはよくわかりませんが、これを簡単に にすることができるようですEnhancedUserType。これにより、実装がより用途が広がる可能性があります。プロジェクトで LGPL ライセンスのソース コードの使用が許可されている場合は、 の実装EnumType独自の のテンプレートとして使用できますEnumSetType。特に、コードのすべての「序数として保存」部分を破棄できるため、それを適応させるのは簡単なはずです。

独自のUserTypeを作成しEnumSetたら、対応するフィールドにその で注釈を付けることができます@Type。または、休止状態の構成で、セットアップにそのようなものがあれば。その型を使用してすべてのインスタンスを自動的にマップするために、型をどこかに登録する方法さえあるかもしれませんが、EnumSetこれが望ましいか、可能かどうかを判断するには、この休止状態全体についてほとんど知りません。@Enumerated注釈がEnumType実装にどのようにマップされるかはまだわかりません。

適切なキーワード ( UserType EnumSet split) を使用すると、Web 上でいくつかの実装を見つけることができます。したがって、独自のコードを記述する必要さえなく、これらのソリューションの 1 つを含めるだけで済みます。使い方の簡単な説明が付いているものもあります。

于 2012-07-02T13:28:10.580 に答える