web-dev-qa-db-ger.com

Die Nicht-Null-Eigenschaft verweist auf einen Null- oder Übergangswert für einen persistenten Wert

Ich versuche, zwei verschiedene Entitäten mit JPA1 mit der Hibernate-Implementierung zu persistieren. Der Code hierfür ist wie folgt:

Übergeordnete Entitätsklasse

@Entity
@Table(name = "parent")
public class Parent implements Serializable {

    {...}
    private Child child;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "child_id", nullable = "false")
    public Child getChild() {
        return child;
    }

    public void setChild(Child child) {
        this.child = child;
}

Untergeordnete Entitätsklasse 

@Entity
@Table(name = "child")
public class Child implements Serializable {

    private Integer id;

    @Id
    @Column(name = "child_id")
    public Integer getId() {
        return id;
    }

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

Testfall

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:META-INF/application.xml")
@Transactional
public class ParentTest extends TestCase {

    @PersistenceContext
    private EntityManager entityManager;

    @Test
    public void testSave() {
        Child child = new Child();
        child.setId(1);

        Parent parent = new Parent();
        parent.setChild(child);

        entityManager.persist(parent.getChild());
        entityManager.persist(parent); // throws the exception
    }
}

Entity Manager und Transaktion in application.xml

<tx:annotation-driven transaction-manager="transactionManager" /> 

<jee:jndi-lookup id="dataSource" jndi-name="Java:/jdbc/myds" expected-type="javax.sql.DataSource" /> 

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="packagesToScan" value="com.mypackage" />
    <property name="dataSource" ref="dataSource" /> 
    <property name="jpaVendorAdapter"› 
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
    </property>
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.dialect>org.hibernate.dialect.Oracle10gDialect</prop>
        </props>
    </property>
</bean> 

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" /> 
</bean>

Beim Versuch, das übergeordnete Objekt einzufügen, löst der Ruhezustand eine PropertyValueException aus, die besagt, dass child null oder transient ist, obwohl das child vor diesem Vorgang erstellt und beibehalten wurde. Das Seltsame ist, dass dies nur beim Komponententest fehlschlägt, und in der realen Anwendung mit einem bereits eingefügten Kind funktioniert dies genauso wie erwartet.

PS: Ich bin mir ziemlich bewusst, dass ich ein Kind mit einer Kaskadenpersistenz aufzeichnen könnte, aber das ist hier nicht die Idee. Ich möchte nur prüfen, ob diese beiden unabhängig voneinander arbeiten.

11
renke

Das Problem hierbei ist, dass Sie die übergeordnete Tabelle mit den gesetzten Werten beibehalten. Wenn sie bestehen bleibt, muss die untergeordnete Tabellen-ID bereits gespeichert werden, da es sich um einen Fremdschlüssel handelt und es sich daher nicht um NULL-Eigenschaftsreferenzen handelt ein Nullwert.

    @Test
    public void testSave() {
        Child child = new Child();
        child.setId(1);
        entityManager.persist(child); 

        Parent parent = new Parent();
        parent.setChild(child);

        entityManager.persist(parent); 
    }

Versuchen Sie dies, um zuerst das untergeordnete Element und dann das übergeordnete Element zu speichern

8
muthukumar

Das erste, was Sie mit @ManyToOne in Parent verwenden, sagt mir, dass Sie mehr als einen Elternteil für ein Child-Objekt haben. Ich denke, das ist nicht der Fall.

Gemäß Ihrer Klassenstruktur kann ich verstehen, dass Sie eine OneToOne-Zuordnung zwischen übergeordneten und untergeordneten Entitäten haben.

In Bezug auf die Ausnahme gibt es einen Grund, warum Sie keine Kaskaden zwischen Parent und Child verwenden, um die Zuordnung für das Speichern, Aktualisieren und Löschen automatisch durchzuführen. Wenn Sie nicht darüber nachgedacht haben, können Sie es versuchen, indem Sie die unten angegebene Konfiguration wie hier angegeben einstellen: Beispiel für Eltern/Kind - Hibernate

cascade = {CascadeType.ALL}

Ich würde jedoch vorschlagen, die Zuordnung von ManyToOne zu OneToOne zwischen Child und Parent zu ändern.

Lass es mich wissen, bitte.

Abgesehen davon, dass Sie ein Elternteil mit einem FK-Problem zu einem Kind haben, ist die Dauerordnung die Ursache Ihres Problems.

Ihr Problem ist im Zusammenhang mit dem Spülen . Nur weil Sie Hibernate angewiesen haben, ein Objekt zu persistieren, bedeutet dies nicht, dass es automatisch Ihre Anfrage bedient. Die Persist-Anforderung wird nur in eine Aktionswarteschlange gestellt, um zur Flush-Zeit zu materialisieren. Ihr zweites Persist findet also einfach die Parent-Entität ohne ein "persistiertes" Kind.

Sie können Ihren Code einfach wie folgt korrigieren:

    Child child = new Child();
    child.setId(1);

    entityManager.persist(parent.getChild());
    entityManager.flush();

    Parent parent = new Parent();
    parent.setChild(child);
    entityManager.persist(parent);
    entityManager.flush;
2
Vlad Mihalcea

Versuche dies:

@ManyToOne(fetch = FetchType.LAZY,optional=false)
@JoinColun(name = "child_id", nullable = "false")
public Child getChild() {
    return child;
}
1
Tkachuk_Evgen

Einige Felder werden mit not-null="true" festgelegt, vor dem Speichern in db ..__ muss ein Wert angegeben werden. Für alle Felder in der übergeordneten Tabelle und für die untergeordnete Tabelle müssen alle Felder mit dem entsprechenden Wert angegeben werden

0
xrcwrn

Versuchen Sie, @ManyToOne(fetch = FetchType.LAZY,cascade=PERSIST, mappedBy="parent") für public Child getChild() anzugeben und nur das übergeordnete Objekt zu erhalten. Beides bleibt bestehen. 

0
DS Stack