Pergunta

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Problem {
    @ManyToOne
    private Person person;
}

@Entity
@DiscriminatorValue("UP")
public class UglyProblem extends Problem {}

@Entity
public class Person {
    @OneToMany(mappedBy="person")
    private List< UglyProblem > problems;
}

Acho que está bem claro o que estou tentando fazer.Espero que a pessoa @ManyToOne seja herdada pela classe UglyProblem.Mas haverá uma exceção dizendo algo como:"Não existe tal propriedade encontrada na classe UglyProblem (mappedBy = "person")".

Tudo o que encontrei foi esse.Não consegui encontrar a postagem de Emmanuel Bernard explicando os motivos disso.


Infelizmente, de acordo com a documentação do Hibernate "Propriedades de superclasses não mapeadas como @MappedSuperclass são ignoradas."

Bem, acho que isso significa que se eu tiver essas duas classes:

public class A {
    private int foo;
}

@Entity
public class B extens A {
}

então campo foo não será mapeado para a classe B.O que faz sentido.Mas se eu tiver algo assim:

@Entity
public class Problem {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

private String name;

public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}
}

@Entity
public class UglyProblem extends Problem {

private int levelOfUgliness;

public int getLevelOfUgliness() {
    return levelOfUgliness;
}

public void setLevelOfUgliness(int levelOfUgliness) {
    this.levelOfUgliness = levelOfUgliness;
}
}

Espero que a classe UglyProblem tenha arquivos id e name e ambas as classes serão mapeadas usando a mesma tabela.(Na verdade, é exatamente isso que acontece, acabei de verificar novamente).Eu tenho esta tabela:

CREATE TABLE "problem" (
    "DTYPE" varchar(31) NOT NULL,
    "id" bigint(20) NOT NULL auto_increment,
    "name" varchar(255) default NULL,
    "levelOfUgliness" int(11) default NULL,
    PRIMARY KEY  ("id")
) AUTO_INCREMENT=2;

Voltando à minha pergunta:

Espero que a pessoa @ManyToOne seja herdada pela classe UglyProblem.

Espero isso porque todos os outros campos mapeados são herdados e não vejo nenhum motivo para abrir essa exceção para relacionamentos ManyToOne.


Sim, eu vi isso.Na verdade, usei a solução somente leitura para o meu caso.Mas a minha pergunta foi "Porquê..." :).Eu sei que existe uma explicação dada por um membro da equipe de hibernação.Não consegui encontrar e por isso perguntei.

Quero descobrir a motivação desta decisão de design.

(se você estiver interessado em como enfrentei esse problema:Herdei um projeto construído usando o hibernate 3.Era o Jboss 4.0.alguma coisa + o hibernate já estava lá (você baixaria tudo junto).Eu estava migrando este projeto para o Jboss 4.2.2 e descobri que existem mapeamentos herdados de "@OneToMany mappedBy" e funcionou bem na configuração antiga...)

Foi útil?

Solução

Acho que é uma decisão sábia tomada pela equipe do Hibernate.Eles poderiam ser menos arrogantes e deixar claro por que foi implementado dessa forma, mas é assim que Emmanuel, Chris e Gavin funcionam.:)

Vamos tentar entender o problema.Acho que seus conceitos estão "mentindo".Primeiro você diz que muitos Problemas estão associados a Pessoas.Mas, então você diz isso Pessoa tem muitos Problema Feios (e não se relaciona com outros Problemae).Algo está errado com esse design.

Imagine como isso será mapeado para o banco de dados.Você tem uma herança de tabela única, então:

          _____________
          |__PROBLEMS__|          |__PEOPLE__|
          |id <PK>     |          |          |
          |person <FK> | -------->|          |
          |problemType |          |_________ |
          -------------- 

Como o hibernate vai impor o banco de dados para fazer Problema relacionar-se apenas com Pessoas se é tipo de problema é igual UP?Esse é um problema muito difícil de resolver.Então, se você quiser esse tipo de relação, cada subclasse deve estar em sua própria tabela.Isso é o que @MappedSuperclass faz.

PS.:Desculpe pelo desenho feio :D

Outras dicas

No meu caso eu queria usar o tipo de herança SINGLE_TABLE, então usar @MappedSuperclass não era uma opção.

O que funciona, embora não seja muito limpo, é adicionar o arquivo proprietário do Hibernate @Onde cláusula à associação @OneToMany para forçar o tipo nas consultas:

@OneToMany(mappedBy="person")
@Where(clause="DTYPE='UP'")
private List< UglyProblem > problems;

Infelizmente, de acordo com o Hibernate documentação "Propriedades de superclasses não mapeadas como @mappedsuperclass são ignoradas". Eu corri contra isso também.Minha solução foi representar a herança desejada por meio de interfaces, em vez dos próprios beans de entidade.

No seu caso, você poderia definir o seguinte:

public interface Problem {
    public Person getPerson();
}

public interface UglyProblem extends Problem {
}

Em seguida, implemente essas interfaces usando uma superclasse abstrata e duas subclasses de entidade:

@MappedSuperclass
public abstract class AbstractProblemImpl implements Problem {
    @ManyToOne
    private Person person;

    public Person getPerson() {
        return person;
    }
}

@Entity
public class ProblemImpl extends AbstractProblemImpl implements Problem {
}

@Entity
public class UglyProblemImpl extends AbstractProblemImpl implements UglyProblem {
}

Como um benefício adicional, se você codificar usando as interfaces em vez dos beans de entidade reais que implementam essas interfaces, será mais fácil alterar os mapeamentos subjacentes posteriormente (menos risco de quebrar a compatibilidade).

Eu acho que você precisa anotar seu Problema superclasse com @MappedSuperclass em vez de @Entidade.

Eu descobri como resolver o problema OneToMany mappedBy.

Na classe derivada UglyProblem da postagem original.O método de retorno de chamada precisa estar na classe derivada e não na classe pai.

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@ForceDiscriminator
public class Problem {

}

@Entity
@DiscriminatorValue("UP")
public class UglyProblem extends Problem {
    @ManyToOne
    private Person person;
}

@Entity
public class Person {
    @OneToMany(mappedBy="person")
    private List< UglyProblem > problems;
}

Encontrei o molho secreto para usar pelo menos o Hibernate. http://docs.jboss.org/hibernate/stable/annotations/api/org/hibernate/annotations/ForceDiscriminator.html O @ForceDiscriminator faz o @OneToMany homenagear o discriminador

Requer anotações de hibernação.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top