2012-03-06 9 views
2

いくつかのクライアントを持つ会社を表すためのModelオブジェクトと、企業とクライアントの組み合わせと複数の請求書の行からなる請求書オブジェクトを作成しました。私は、次のモデルオブジェクトを作成しました:再生!

@Entity 
public class Company extends Model { 
    @OneToMany(mappedBy="company") 
    public Set<Client> clients; 
} 

@Entity 
public class Client extends Model { 
    @ManyToOne 
    public Company company; 
} 

@Entity 
public class Invoice extends Model { 
    @ManyToOne 
    public Company company; 
    @ManyToOne 
    public Client client; 
    @OneToMany(mappedBy="invoice", cascade=CascadeType.ALL) 
    public Set<InvoiceLine> invoiceLines; 
} 

@Entity 
public class InvoiceLine extends Model { 
    @ManyToOne 
    public Invoice invoice; 
} 

テスト:

@Test 
public void testModels() { 
    Client client = createClient(); 
    Company company = createCompany(); 
    company.clients = new HashSet<Client>(); 
    company.clients.add(client); 
    company.save(); 

    Invoice invoice = createInvoice(client, company); 
    InvoiceLine invoiceLine1 = createInvoiceLine(invoice); 
    InvoiceLine invoiceLine2 = createInvoiceLine(invoice); 
    Set<InvoiceLine> invoiceLines = new HashSet<InvoiceLine>(); 
    invoiceLines.add(invoiceLine1); 
    invoiceLines.add(invoiceLine2); 
    invoice.invoiceLines = invoiceLines; 
    invoice.save(); 

    Company retrievedCompany = Company.find("byName", company.name).first(); 
    assertNotNull(retrievedCompany); 
    assertEquals(1, retrievedCompany.clients.size()); 
    assertEquals(2, InvoiceLine.count()); 

    assertEquals(1, Invoice.deleteAll()); 
    assertNull(Invoice.all()); 
    assertNull(InvoiceLine.all()); 

}

2つの請求書のラインで請求書を作成し、テストを実行し、この請求書を削除しようと、次のエラーが表示されます。

org.h2.jdbc.JdbcSQLException: Referential integrity constraint violation: "FK3004B0A1F4110EF6: PUBLIC.INVOICELINE FOREIGN KEY(INVOICE_ID) REFERENCES >PUBLIC.INVOICE(ID)"; SQL statement: delete from Invoice [23003-149]

私は間違っていますか?

+0

テストのコードを追加してください。 –

+0

テストが追加されました。 –

答えて

3

invoice.delete()でこれを試しましたか?問題は、deleteAll()が削除操作をカスケードしないということです。 delete()EntityManagerremove()方法を使用しながら

deleteAll()

は、内部javax.persistence.Query使用します。 JPAのカスケードはJPAによって処理され、データベースでは処理されず、JPAはdeleteAll()のようなバルク削除をカスケードしません。
Check this link for more info on bulk delete/update

また、Invoiceを親としてcreateInvoiceLine()に設定している場合は、InvoiceLineエンティティをInvoiceに追加することは冗長です。アサートを実行する前にinvoice.refresh()を実行してください。

おそらく、以下の単体テストが問題を解決するかもしれません。 Parent1Invoiceと同じです。 Child1はあなたのInvoiceLineと似ていますが

import java.util.*; 
import javax.persistence.*; 
import org.junit.*; 
import play.test.*; 
import models.*; 

public class Parent1Test extends UnitTest { 

    public Parent1 p; 
    public Child1 c1; 
    public Child1 c2; 
    public Child1 c3; 

    @Before 
    public void setUp() { 
     Fixtures.deleteAllModels(); 

     p = new Parent1(); 
     c1 = new Child1(); 
     c2 = new Child1(); 
     c3 = new Child1(); 
    } 

    public void byAddingParentToChilds() { 
     c1.parent = p; 
     c2.parent = p; 
     c3.parent = p; 

     c1.save(); 
     c2.save(); 
     c3.save(); 
     p.refresh(); 
    } 

    @Test 
    public void testByAddingParentToChilds() { 
     byAddingParentToChilds(); 
     assertEquals(p.id, c1.parent.id); 
     assertEquals(3, Child1.count()); 
    } 

    public void byAddingChildsToParent() { 
     p.childs = new ArrayList<Child1>(); 
     p.childs.add(c1); 
     p.childs.add(c2); 
     p.childs.add(c3); 
     p.save(); 
    } 

    @Test 
    public void testByAddingChildsToParent() { 
     // By adding childs 
     byAddingChildsToParent(); 

     c1.refresh(); 
     assertEquals(3, Child1.count()); 
     // This will be null, because you added the childs to the 
     // parent while the childs are the owning side of the 
     // relation. 
     assertNull(c1.parent); 
    } 

    @Test 
    public void testDeletingAfterAddingParentToChilds() { 
     byAddingParentToChilds(); 
     p.delete(); 
     assertEquals(0, Parent1.count()); 
     assertEquals(0, Child1.count()); 
    } 

    @Test 
    public void testDeletingAfterAddingChildsToParent() { 
     byAddingChildsToParent(); 
     p.delete(); 
     assertEquals(0, Parent1.count()); 
     assertEquals(0, Child1.count()); 
    } 

    @Test(expected=PersistenceException.class) 
    public void testDeleteAllAfterAddingParentToChilds() { 
     byAddingParentToChilds(); 
     // The cascading doesn't work for deleteAll() so this line 
     // will throw an exception because the child elements still 
     // reference the parent. 
     assertEquals(1, Parent1.deleteAll()); 
    } 

    @Test 
    public void testDeleteAllAfterAddingChildsToParent() { 
     byAddingChildsToParent(); 
     assertEquals(1, Parent1.deleteAll()); 
     assertEquals(0, Parent1.count()); 
     // Again the cascading doesn't work for deleteAll() 
     assertEquals(3, Child1.count()); 
    } 

} 
+0

あなたの明確な説明をありがとう! –

+0

1つの質問では、メソッドbyAddingParentToChilds()でまず親を保存してから、子を親のリフレッシュに続けます。これは、親(親が永続的にカスケードされていると仮定)の保存が同じに達するのに十分でなければならないので、やや冗長であると思われます。 –

+0

正解で答えが確定しました:) – maartencls

0

すべての請求書を削除しようとしていますが、依然としていくつかのInvoiceLinesがリンクされています。

最初に請求書の行を削除し、請求書を削除してみてください。

+1

ご返信ありがとうございます。この問題は、PlayではなくJPAに関連しているようです。フレームワーク。私が望む振る舞いは、invoiceLinesは関連する請求書が削除されると自動的に削除されるということです。私は、CascadeType.ALLとorphanRemovalをtrueに設定して追加することで、この動作が発生すると思っていましたが、代わりにinvoiceLinesを削除したinvoice behoreを削除して整合性制約違反を取得しました。 –