2012-07-24 50 views
1

我有我的帳戶實體中的訂單列表。出於這個原因,我的訂單實體有一個外鍵返回到它的父命令。首先保存父帳戶直到其父帳戶保存的最佳方法是什麼?我不想在沒有帳戶的情況下在數據庫中存在任何訂單。 爲了更好地解釋 這裏是我的Order類對外鍵的Db限制

@DatabaseTable 
public class Order{ 

    private static final long serialVersionUID = 1L; 

    @DatabaseField(id = true) 
    private long id; 

    @DatabaseField(foreign = true) 
    private Account account; 

} 

這裏是我的賬戶類

@DatabaseTable 
public class Account { 
    private static final long serialVersionUID = 1L; 

    @DatabaseField(id = true) 
    private int id; 

    @ForeignCollectionField 
    private ForeignCollection<Order> orders; 

    public ForeignCollection<Order> getOrders() { 
     return orders; 
    } 

    public void setOrders(ForeignCollection<Order> orders) { 
     this.orders = orders; 
    } 
} 

的事情是我能夠保存的訂單沒有它的帳戶設定。有沒有辦法通過在訂單的帳戶字段中設置一些屬性來防止這種情況? 我已經省略了一些代碼,但我知道上面的關係工作正常,因爲我可以檢索給定帳戶A1的訂單Or1,Or2或Or3當我設置每個訂單中的帳戶字段= A1

回答

0

我粘貼整個測試數據庫應用程序的源代碼。這應該可以解決你的問題。

我有一個活動類,將提供您的UI放置訂單和支持xml文件,和一個DbHandler類來執行數據庫操作。

這裏是活動代碼。

package com.test; 

import android.app.Activity; 
import android.app.AlertDialog; 
import android.content.DialogInterface; 
import android.database.sqlite.SQLiteConstraintException; 
import android.os.Bundle; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.Button; 
import android.widget.EditText; 

public class TestActivity extends Activity implements OnClickListener{ 

    private EditText accountId = null; 
    private EditText orderNumber = null; 
    private Button submit = null; 

    private DBHandler dbHandler = null; 


    @Override 
    public void onCreate(Bundle savedInstanceState) { 

     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 

     setupUiElementProperties(); 
     dbHandler = new DBHandler(this); 
    } 


    private void setupUiElementProperties() { 

     accountId = (EditText)findViewById(R.id.accountEditText); 
     orderNumber = (EditText)findViewById(R.id.orderNoEditText); 
     submit = (Button)findViewById(R.id.submit); 
     submit.setOnClickListener(this); 
    } 


    public void onClick(View v) { 

     try { 

      dbHandler.placeOrder(Integer.parseInt(accountId.getText().toString().trim()), 
        Integer.parseInt(orderNumber.getText().toString().trim())); 

      showAlert("ORDER PLACED SUCCESSFULLY"); 
      System.out.println("DONE.."); 
     }catch (SQLiteConstraintException ex) { 

      System.out.println("SQLITE EXCEPTIOn: " + ex.getMessage()); 

      showAlert("THIS ACCOUNT DOES NOT EXISTS"); 
     }catch (Exception e) { 

      System.out.println("Exceptionn: " + e.getMessage()); 
     } 
    } 

    private void showAlert(String message) { 

     new AlertDialog.Builder(TestActivity.this) 
     .setTitle("Alert") 
     .setMessage(message) 
     .setPositiveButton("ok", new DialogInterface.OnClickListener(){ 
      public void onClick(DialogInterface dlg, int sumthin) {} 
     }) 
     .show(); 
    } 
} 

這是main.xml中

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    android:orientation="vertical" > 


    <EditText 
     android:id="@+id/accountEditText" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentRight="true" 
     android:layout_alignParentTop="true" 
     android:layout_margin="10dp" 
     android:layout_toRightOf="@+id/accountNoLabel" android:inputType="number"> 

     <requestFocus /> 
    </EditText> 

    <TextView 
     android:id="@+id/accountNoLabel" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignBaseline="@+id/accountEditText" 
     android:layout_alignBottom="@+id/accountEditText" 
     android:layout_alignParentLeft="true" 
     android:text="Account Id" android:layout_marginLeft="5dp"/> 




    <EditText 
     android:id="@+id/orderNoEditText" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignLeft="@+id/accountEditText" 
     android:layout_alignRight="@+id/accountEditText" 
     android:layout_below="@+id/accountEditText" android:inputType="number"/> 

    <TextView 
     android:id="@+id/orderLabel" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignBaseline="@+id/orderNoEditText" 
     android:layout_alignBottom="@+id/orderNoEditText" 
     android:layout_alignLeft="@+id/accountNoLabel" 
     android:text="Order No" /> 

    <Button 
     android:id="@+id/submit" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentBottom="true" 
     android:layout_centerHorizontal="true" 
     android:text="Submit" /> 

</RelativeLayout> 

最後的DbHandler類

package com.test; 

import android.content.ContentValues; 
import android.content.Context; 
import android.database.sqlite.SQLiteConstraintException; 
import android.database.sqlite.SQLiteDatabase; 
import android.database.sqlite.SQLiteOpenHelper; 

public class DBHandler extends SQLiteOpenHelper { 

    private SQLiteDatabase sqliteDatabaseInstance_ = null; 

    public DBHandler(Context context){ 

     super(context, "TESTDATABASE.db", null, 1); 
     sqliteDatabaseInstance_ = getWritableDatabase(); 
     sqliteDatabaseInstance_.execSQL("PRAGMA foreign_keys = ON;"); 
    } 

    @Override 
    public void onCreate(SQLiteDatabase db) { 

     try { 

      db.execSQL("CREATE TABLE ACCOUNT (accountId INTEGER PRIMARY KEY, name TEXT)"); 
      insertAccount(1234, "xyz", db); 
      db.execSQL("CREATE TABLE ORDER_DETAILS (orderNo INTEGER, accountId INTEGER," + 
        "FOREIGN KEY (accountId) REFERENCES ACCOUNT(accountId))"); 
     }catch (SQLiteConstraintException sqliteConstraintException) { 

      System.out.println("sqliteConstraintException: " + sqliteConstraintException.getMessage()); 
     }catch (Exception e) { 

      System.out.println("Exception in DBHandler.onCreate: "+e.getMessage()); 
     } 
    } 

    @Override 
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {} 

    public void placeOrder(int accountNo, int orderNo) throws SQLiteConstraintException{ 

     ContentValues cv = new ContentValues(); 
     cv.put("accountId", accountNo); 
     cv.put("orderNo", orderNo); 
     sqliteDatabaseInstance_.insertOrThrow("ORDER_DETAILS", null, cv); 
    } 


    private void insertAccount(int accId, String accountHolderName, SQLiteDatabase db) { 

     ContentValues cv = new ContentValues(); 
     System.out.println("db: " + db); 
     System.out.println("accountId: " + accId) ; 
     System.out.println("accountHolderName: " + accountHolderName); 
     cv.put("accountId", accId); 
     cv.put("name", accountHolderName); 
     db.insertOrThrow("ACCOUNT", null, cv); 
    } 
} 

XML代碼實際上ü不會是人工添加的訂單號(ORDER_DETAILS表)。該字段必須自動增量並輸入數據庫。

我在DbHandler中添加了insertAccount(),因爲「Account」表沒有任何條目。使用這種方法,我添加了一個帳戶,帳戶ID爲「1234」。

這應該是烏爾輸出:

場景1 帳戶NO:1234 順序號:453412

該條目將被插入到數據庫中作爲帳戶ID 1234存在於ACCOUNT表和一個顯示成功更新警報。

方案2 賬戶2343 順序編號:14523

此項目將不會被用作外鍵約束失敗受理。所以你會得到一個警告說「這個帳戶不存在」。

我的數據庫可能與您的需求不一樣,但我希望這應該足以幫助您解決問題。

使用SQLITEBROWSER查看數據。

烏爾數據庫文件應該是下.........

轉到文件瀏覽器----->數據------>數據------> COM .test -----> TESTDATA。db

+0

感謝的是,它解決了我問題沒問題,但我想避免在我的應用程序中有任何SQL,如果可能的話。我正在嘗試使用ORMlite解決方案來解決此問題。 – MayoMan 2012-07-25 14:57:24

-1

@ user965895:我沒看見你有標記ormlite。我不知道。我建議的代碼是SQLite。 Android內置輕量數據庫SQLite,你可以使用它。

+0

不用擔心,謝謝你的回覆。我正在使用SQLlite。我運行了您建議的「PRAGMA foreign_keys = ON」的SQL,但它仍然允許我在數據庫中不存在它所引用的帳戶時創建訂單 – MayoMan 2012-07-24 10:06:34

+0

您兩次回答了此問題?這應該是一個評論。請刪除。 – Gray 2012-07-24 15:58:56

+0

@ user965895:你如何知道插入的值?您是否使用任何瀏覽器查看數據?如果不使用sqliteBrowser查看你的數據。你試過cursor.getcount的東西嗎?這應該工作(手動處理)。但我會建議使用外鍵而不是手動處理。 – vinod 2012-07-25 05:55:30

0

抱歉,延遲應答。幾件事情在這裏嘗試。

您的account字段在您的Order應該有canBeNull = false以確保該字段已被分配。如果您嘗試插入您的Order,而無需一個Account集它

@DatabaseField(foreign = true, canBeNull = false) 
private Account account; 

這會拋出異常。但是,您可以將account文件設置爲Account,該文件具有而不是已插入數據庫。解決這個問題的一個方法是使Account.id字段成爲Integer對象(而不是int原語),因此如果它尚未設置,它將是null

// this is an Integer object so it is null if it has not been set 
@DatabaseField(id = true) 
private Integer id; 

這時如果Account.id領域還沒有確定,它會如果您創建與AccountOrder拋出異常。順便說一句,這聽起來像你可能想要@DatabaseField(generatedId = true)Integer領域也將爲此工作。

最後,您還可以覆蓋你的orderDao.create(...)方法拋出一個異常,如果您嘗試創建一個Orderaccount場是null或者如果account.id字段的值爲0

// we have a custom DAO for this class 
@DatabaseTable(daoClass = MyOrderDao.class) 
public static class Order { 
     ... 
} 

public static class MyOrderDao extends BaseDaoImpl<Order, Integer> { 
    public MyOrderDao(ConnectionSource connectionSource) throws SQLException { 
     super(connectionSource, Order.class); 
    } 

    @Override 
    public int create(Order order) throws SQLException { 
     if (order.account == null) { 
      throw new SQLException("Order's account field is null"); 
     } 
     if (order.account.id == 0) { 
      throw new SQLException("Order's account field has a 0 id"); 
     } 
     return super.create(order); 
    } 
}