Android 关于DB室中的关系,我应该采用哪种方法?
我正在做一个简单的商店应用程序来了解更多关于Android中Room DB的信息,目前我有点困惑,当涉及到关系和嵌套对象时,哪种方法是最好的 场景:客户从商店选择商品并订购。之后,数据库用订单ID更新客户表,以便可以在数据库中搜索客户订单。订单表具有该特定订单中的产品ID。在客户“账户”页面(应用程序内部),包括产品在内的所有订单应显示所有必要信息(例如订单id、产品名称、价格、数量等) 我做了这个草图来说明三个表:客户、订单和产品Android 关于DB室中的关系,我应该采用哪种方法?,android,database,android-room,Android,Database,Android Room,我正在做一个简单的商店应用程序来了解更多关于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部分
最好参考诸如“”之类的链接非常有趣!我尝试过你的方法,它似乎很有魅力。但我确实对你的这种逻辑有一些疑问:我想删除引用类,以便客户表包含一个名为
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