Android 关于DB室中的关系,我应该采用哪种方法?

Android 关于DB室中的关系,我应该采用哪种方法?,android,database,android-room,Android,Database,Android Room,我正在做一个简单的商店应用程序来了解更多关于Android中Room DB的信息,目前我有点困惑,当涉及到关系和嵌套对象时,哪种方法是最好的 场景:客户从商店选择商品并订购。之后,数据库用订单ID更新客户表,以便可以在数据库中搜索客户订单。订单表具有该特定订单中的产品ID。在客户“账户”页面(应用程序内部),包括产品在内的所有订单应显示所有必要信息(例如订单id、产品名称、价格、数量等) 我做了这个草图来说明三个表:客户、订单和产品 问题:这里什么是@外键,@嵌入式和@关系?首先,您的场景/结

我正在做一个简单的商店应用程序来了解更多关于Android中Room DB的信息,目前我有点困惑,当涉及到关系和嵌套对象时,哪种方法是最好的

场景:客户从商店选择商品并订购。之后,数据库用订单ID更新客户表,以便可以在数据库中搜索客户订单。订单表具有该特定订单中的产品ID。在客户“账户”页面(应用程序内部),包括产品在内的所有订单应显示所有必要信息(例如订单id、产品名称、价格、数量等)

我做了这个草图来说明三个表:客户、订单和产品


问题:这里什么是
@外键
@嵌入式
@关系

首先,您的场景/结果模式可能缺乏

也就是说,订单到产品的关系应该是一种多人关系。也就是说,许多产品可以被许多ODR引用。这种关系通常由引用表处理

因此,您将有一个Customer表,一个Order表,其中有一列引用客户,一个Product表不引用任何内容,一个reference表有两列,一列引用产品,另一列引用产品

@ForeignKey定义了一个要求,即用于引用/关联/关联的列必须引用父级中的值

假设客户有一列(或多个唯一标识客户的列,比如一个客户有1列,另一个客户有2列,以此类推)。然后订单将有一列引用下订单的客户(假设每个客户都有订单)。然后外键添加一个约束(规则)这要求订单(子订单)中的值必须是值,并且存在于客户表(父订单)的引用列中。如果插入(新订单)或更新(客户或订单)或删除(客户)导致此要求,则将导致冲突(错误)

为了简化引用/关系完整性的维护,@ForeignKey还可以包括在更新或删除父值时采取的更新和删除操作(级联可能是最常用的选项)(级联对父值的子项进行更改或删除,即将更改级联到子项)

这种关系不需要外键,但可以提供帮助

@Embedded包括要包含在类或实体中的实体(或非实体类)的字段(数据库透视中的列)

@relationship允许提取/包含相关数据(实体)

示例/演示 考虑定义表的以下实体(根据建议的模式):-

Customer.java:- Product.java java(订单可以拥有的一个客户的外键) OrderProductReference.java(参考表) OrderWithProduct.java 这将嵌入OrderProductReference(表),并包含要包含(如Emdedding)所引用的订单和产品的关系

public class OrderWithProduct {

    @Embedded
    OrderProductReference orderProductReference;
    @Relation( entity = Order.class, parentColumn = "orderIdReference", entityColumn = "orderId")
    Order order;
    @Relation(entity = Product.class, parentColumn = "productIdReference", entityColumn = "productId")
    Product product;
}
  • i、 这是问题的第2和第3部分
java(为了方便起见,所有Dao的组合) 并将其捆绑在一起,进行演示 MainActivity.java
最好参考诸如“”之类的链接非常有趣!我尝试过你的方法,它似乎很有魅力。但我确实对你的这种逻辑有一些疑问:我想删除引用类,以便客户表包含一个名为
order\u id
的新列,其中包含客户订单,以及应该包含
product\u id
-这是否违反了任何有关Sql(或Room)的惯例?@Delice如果一个客户有多个订单怎么办?如果一个订单有多个产品怎么办?(两者都是修辞性的)。您必须存储一份订单/产品列表,以处理复杂的问题。因此,简言之,这种设计违背了所谓的标准化。或许您可以阅读一下(搜索标准化将发现许多其他概述)
@Entity
public class Product {

    @PrimaryKey
    Long productId;
    String productName;

    public Product(){}

    @Ignore
    public Product(String productName) {
        this.productName = productName;
    }

    public Long getProductId() {
        return productId;
    }

    public void setProductId(Long productId) {
        this.productId = productId;
    }

    public String getProductName() {
        return productName;
    }

    public void setProductName(String productName) {
        this.productName = productName;
    }
}
@Entity(
        foreignKeys = @ForeignKey(
                entity = Customer.class,
                parentColumns = "customerId",
                childColumns = "customerReference",
                onUpdate = ForeignKey.CASCADE,
                onDelete = ForeignKey.CASCADE
        ),
        indices = {@Index(value = "customerReference")}
)
public class Order {

    @PrimaryKey
    Long orderId;
    Long customerReference;

    public Order(){}

    @Ignore
    public Order(long customerReference) {
        this.customerReference = customerReference;
    }

    public Long getOrderId() {
        return orderId;
    }

    public void setOrderId(Long orderId) {
        this.orderId = orderId;
    }

    public Long getCustomerReference() {
        return customerReference;
    }

    public void setCustomerReference(Long customerReference) {
        this.customerReference = customerReference;
    }
}
@Entity(
        primaryKeys = {"orderIdReference","productIdReference"},
        foreignKeys = {
                @ForeignKey(
                        entity = Order.class,
                        parentColumns = {"orderId"},
                        childColumns = "orderIdReference",
                        onUpdate = ForeignKey.CASCADE,
                        onDelete = ForeignKey.CASCADE
                ),
                @ForeignKey(
                        entity = Product.class,
                        parentColumns = {"productId"},
                        childColumns = "productIdReference",
                        onUpdate = ForeignKey.CASCADE,
                        onDelete = ForeignKey.CASCADE
                )
        },
        indices = {@Index(value = "productIdReference")}
        )
public class OrderProductReference {

    long orderIdReference;
    long productIdReference;

    public OrderProductReference(){}

    @Ignore
    public OrderProductReference(long customerIdReference, long productIdReference) {
        this.orderIdReference = customerIdReference;
        this.productIdReference = productIdReference;
    }

    public long getCustomerIdReference() {
        return orderIdReference;
    }

    public void setCustomerIdReference(long customerIdReference) {
        this.orderIdReference = customerIdReference;
    }

    public long getProductIdReference() {
        return productIdReference;
    }

    public void setProductIdReference(long productIdReference) {
        this.productIdReference = productIdReference;
    }
}
public class OrderWithProduct {

    @Embedded
    OrderProductReference orderProductReference;
    @Relation( entity = Order.class, parentColumn = "orderIdReference", entityColumn = "orderId")
    Order order;
    @Relation(entity = Product.class, parentColumn = "productIdReference", entityColumn = "productId")
    Product product;
}
@Dao
public interface AllDao {

    @Insert
    long insertCustomer(Customer customer);

    @Insert
    long insertProduct(Product product);

    @Insert
    long insertOrder(Order order);

    @Insert
    long insertProductInOrder(OrderProductReference orderProductReference);

    @Transaction
    @Query("SELECT * FROM OrderProductReference")
    List<OrderWithProduct> getAllOrdersWithProducts();

    @Query("SELECT * FROM Customer WHERE customerId = :customerId")
    Customer getCustomerById(long customerId);
}
@androidx.room.Database(entities = {Customer.class,Product.class,Order.class, OrderProductReference.class}, version = 1)
public abstract class Database extends RoomDatabase {

    abstract AllDao allDao();
}
public class MainActivity extends AppCompatActivity {
    Database database;
    AllDao allDao;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        database = Room.databaseBuilder(this,Database.class,"mydatabase")
                .allowMainThreadQueries()
                .build();
        allDao = database.allDao();
        long custid_fred = allDao.insertCustomer(new Customer("Fred"));
        long custid_mary = allDao.insertCustomer(new Customer("Mary"));

        long prod_x = allDao.insertProduct(new Product("X"));
        long prod_y = allDao.insertProduct(new Product("Y"));
        long prod_z = allDao.insertProduct(new Product("Z"));

        long order1_fred = allDao.insertOrder(new Order(custid_fred));
        long order2_fred = allDao.insertOrder(new Order(custid_fred));
        long order1_mary = allDao.insertOrder(new Order(custid_mary));

        long opr_ord1_prdx_fred = allDao.insertProductInOrder(new OrderProductReference(order1_fred,prod_x));
        long opr_ord1_prdz_fred = allDao.insertProductInOrder(new OrderProductReference(order1_fred,prod_z));
        long opr_ord1_prdy_mary = allDao.insertProductInOrder(new OrderProductReference(order1_mary,prod_y));
        long opr_ord2_prdy_fred = allDao.insertProductInOrder(new OrderProductReference(order2_fred,prod_y));

        List<OrderWithProduct> orderWithProducts = allDao.getAllOrdersWithProducts();
        for (OrderWithProduct owp: orderWithProducts) {
            Customer currentCustomer = allDao.getCustomerById(owp.order.getCustomerReference());
            Order currentOrder = owp.order;
            Product currentProduct = owp.product;
            Log.d("DBINFO",
                    "Customer = " + currentCustomer.getCustomerName() +
                            " Order = " + currentOrder.getOrderId() +
                            " Product = " + currentProduct.getProductName()
            );
        }

        /*##### INSERT INVALID FOREIGN KEY #####*/
        long ooops = allDao.insertOrder(new Order(1000 /*<<<<<<<<<< NOT A CUSTOMER ID */));
    }
}
2019-12-31 23:51:56.715 D/DBINFO: Customer = Fred Order = 1 Product = X
2019-12-31 23:51:56.716 D/DBINFO: Customer = Fred Order = 1 Product = Z
2019-12-31 23:51:56.717 D/DBINFO: Customer = Mary Order = 3 Product = Y
2019-12-31 23:51:56.718 D/DBINFO: Customer = Fred Order = 2 Product = Y




2019-12-31 23:51:56.719 D/AndroidRuntime: Shutting down VM
2019-12-31 23:51:56.721 E/AndroidRuntime: FATAL EXCEPTION: main
    Process: a.a.so59542439roomcustomerorderproducts, PID: 28703
    java.lang.RuntimeException: Unable to start activity ComponentInfo{a.a.....MainActivity}: android.database.sqlite.SQLiteConstraintException: FOREIGN KEY constraint failed (code 787 SQLITE_CONSTRAINT_FOREIGNKEY)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3270)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7356)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
     Caused by: android.database.sqlite.SQLiteConstraintException: FOREIGN KEY constraint failed (code 787 SQLITE_CONSTRAINT_FOREIGNKEY)
        at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
        at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:879)
        at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:790)
        at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:88)
        at androidx.sqlite.db.framework.FrameworkSQLiteStatement.executeInsert(FrameworkSQLiteStatement.java:51)
        at androidx.room.EntityInsertionAdapter.insertAndReturnId(EntityInsertionAdapter.java:114)
        at a.a.so59542439roomcustomerorderproducts.AllDao_Impl.insertOrder(AllDao_Impl.java:139)
        at a.a.so59542439roomcustomerorderproducts.MainActivity.onCreate(MainActivity.java:53)
        at android.app.Activity.performCreate(Activity.java:7802)
        at android.app.Activity.performCreate(Activity.java:7791)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016) 
        at android.os.Handler.dispatchMessage(Handler.java:107) 
        at android.os.Looper.loop(Looper.java:214) 
        at android.app.ActivityThread.main(ActivityThread.java:7356) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) 
2019-12-31 23:51:56.742 I/Process: Sending signal. PID: 28703 SIG: 9