0

我必须实现一个使用 LocalDB 来管理离线订单创建的 Web 应用程序。

在这一刻,我正在使用 Dexie for Angular2/Typescript 实现 LocalDB。

我要做的是实现一个数据库以便能够管理:

  • 客户(+1000 条记录)
  • 产品(+2000 条记录)
  • 产品
  • 每个客户定义的价格 +(100.000 条记录)
  • 订单(少量数据)

ETC...

它必须管理大量数据,因为产品、客户和价格是很多或记录......

我的问题是:

如果我必须使用 SQL SERVER 或 MySql 等通用关系数据库来实现这个数据库,那么当我编写临时订单时,我会存储 idMaterial 和数量......

但是我必须在 IndexedDB 中做什么?

最好使用 idMaterial/Qty 存储临时订单,例如 mySql/SqlServer,并通过执行 INNER JOIN 检索产品信息(在需要时),或者最好将产品/价格的所有信息存储在本地表中,以避免INNER JOIN 查询?

我可以在连接超过 2000 多个产品和每个客户定义的 100.000 个产品价格的表之间运行 INNER JOIN 吗?

感谢支持!

4

1 回答 1

5

IndexedDB 的架构很像 SQL 数据库,因为它具有表、行和事务,尽管它们的名称不同(表 = ObjectStore,行 = 对象)。

使用 Dexie,很容易使用外键进行那些典型的连接。IndexedDB 不检查外键的约束,但您可以执行类似于 SQL 连接的查询。

dexie 有一个插件dexie-relationships,可以帮助进行连接查询。

import Dexie from 'dexie'
import relationships from 'dexie-relationships'

class OrdersDB extends Dexie {
  customers: Dexie.Table<Customer, string>;
  products: Dexie.Table<Producs, string>;
  pricesPerCustomer: Dexie.Table<PricePerCustomer, string>;
  orders: Dexie.Table<Order, string>;

  constructor() {
    super ("OrdersDB", {addons: [relationships]});
    this.version(1).stores({
      customers: 'id, name',
      products: 'id, name',
      pricesPerCustomer: `
        id,
        customerId -> customers.id,
        productId -> products.id,
        [customerId+productId]`, // Optimizes compound query (see below)
      orders: `
        id,
        customerId -> customers.id,
        productId -> products.id`
    });
  }
}

interface Customer {
  id: string;
  name: string;
  orders?: Order[]; // db.customers.with({orders: 'orders'})
  prices?: PricesPerCustomer[]; // with({prices: 'pricesPerCustomer'})
}

interface Product {
  id: string;
  name: string;
  prices?: PricesPerCustomer[]; // with({prices: 'pricesPerCustomer'})
}

interface PricePerCustomer {
  id: string;
  price: number;
  currency: string;
  customerId: string;
  customer?: Customer; // with({customer: 'customerId'})
  productId: string;
  product?: Product; // with({product: 'productId'})
}  

interface Order {
  id: string;
  customerId: string;
  customer?: Customer; // with({customer: 'customerId'})
  productId: string;
  product?: Product; // with({product: 'productId'})
  quantity: number;
  price?: number; // When returned from getOrders() below.
  currency?: string; // --"--
}


const db = new OrdersDB();

/* Returns array of Customer with the "orders" and "prices" arrays attached.
*/
async function getCustomersBeginningWithA() {
  return await db.customers.where('name').startsWithIgnoreCase('a')
    .with({orders: 'orders', prices: 'pricesPerCustomer'});
}

/* Returns the price for a certain customer and product using
   a compound query (Must use Dexie 2.0 for this). The query is
   optimized if having a compound index ['customerId+productId']
   declared in the database schema (as done above).
*/
async function getPrice (customerId: string, productId: string) {
  return await db.pricesPerCustomer.get({
    customerId: customerId,
    productId: productId
  });
}

async function getOrders (customerId: string) {
  // Load orders for given customer with product property set.
  const orders = await db.orders.where({customerId: customerId})
    .with({product: 'productId'});

  // Load prices for this each customer/product
  const prices = await Promise.all(orders.map(order =>
    getPrice(customerId, order.id)));

  // Return orders with price and currency properties set:
  return orders.map((order, idx) => {
    const pricePerCustomer = prices[idx];
    return {
      ...order,
      price: pricePerCustomer.price,
      currency: pricePerCustomer.currency
    };
  });
}

请注意,我已将每个主键声明为字符串,因此您必须手动创建每个键。在模式声明中也可以使用自动生成的数字(使用“++id,...”而不是“id,...”)。如果是这样,请将表声明为 Dexie.Table<Customer, number> 而不是 Dexie.Table<Customer, string>。

于 2017-10-13T13:36:58.527 回答