Произвольные «столбцы» из HashMap в запросе гибернации - PullRequest
2 голосов
/ 23 января 2012

Предположим, у меня есть сущность Пользователь

public class User {
    private String username;
    private String password;

    private Map<String, Object> settings = new HashMap<String, Object>();

    //Getters & setters
}

Можно ли использовать ключ карты настроек в запросе?Например:

Criterion crit = mySession.createCriterion(User.class);
crit.add(Restrictions.eq("settings.blah", 1234L));
List<User> results = crit.list();

Или получить доступ к значениям карты через EL?Например:

<h:dataTable value="#{myBean.users}" var="user">
    <h:column>
        <h:outputText value="#{user.blah}"/>
    </h:column>
</h:dataTable>

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

Возможно ли что-то подобное?Как бы я сопоставил это с аннотациями?

Спасибо

РЕДАКТИРОВАТЬ: По сути, я хочу, чтобы реализация «вертикальной таблицы», чтобы я мог иметь произвольные поля, и при этом иметь возможность использоватьсущность как сопоставленный класс.Я не знаю, возможно ли это даже в спящем режиме.

1 Ответ

1 голос
/ 12 апреля 2012

Я никогда не использую Object как значение карты, вы можете использовать String с этим отображением:

@Entity
public class User {

private int _id;
private Map<String, String> _settings;

public User() {

}

@Id
@GeneratedValue
public int getId() {
    return _id;
}

public void setId(int id) {
    _id = id;
}

@ElementCollection
@MapKeyColumn(name = "SETTINGS_KEY")
@CollectionTable(name = "USER_SETTINGS", joinColumns = @JoinColumn(name = "user_id"))
@Column(name = "SETTING")
public Map<String, String> getSettings() {
    return _settings;
}

public void setSettings(Map<String, String> settings) {
    _settings = settings;
}

}

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

@Entity
public class TestSettings {

    private int _id;
    private Map<String, SettingValue<?>> _settings;

    public TestSettings() {

    }

    @Id
    @GeneratedValue
    public int getId() {
        return _id;
    }

    public void setId(int id) {
        _id = id;
    }

    @OneToMany
    @MapKeyColumn(name = "SETTINGS_KEY")
    @CollectionTable(name = "USER_SETTINGS", joinColumns = @JoinColumn(name = "user_id"))
    @Column(name = "SETTING")
    public Map<String, SettingValue<?>> getSettings() {
        return _settings;
    }

    public void setSettings(Map<String, SettingValue<?>> settings) {
        _settings = settings;
    }

}

Абстрактный класс SettingValue:

@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public abstract class SettingValue<V> implements Serializable {

    private static final long serialVersionUID = 3355627640146408150L;

    private Integer _id;

    public SettingValue() {
        super();
    }

    @Id @GeneratedValue
    public Integer getId() {
        return _id;
    }

    public void setId(Integer id) {
        _id = id;
    }

    @Transient
    public abstract V getValue();

    public abstract void setValue(V value);

}

Реализация settingValue String:

@Entity
@PrimaryKeyJoinColumn(name="settingvalue_id", referencedColumnName="id")
public class TextSettingValue extends SettingValue<String> implements Serializable {

    private String _value;

    public TextSettingValue() {
        super();
    }

    @Override
    public void setValue(String value) {
        _value = value;
    }

    @Override
    public String getValue() {
        return _value;
    }

}

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

...