如何插入具有关系的记录

How to insert a record with a Relationship

抱歉,如果这个问题很明显,但我似乎找不到足够的文档。我可能缺乏 restful 方法的知识。如何存储具有关系的记录?

我有一个地方。我想存储 post 到此位置的用户。所以一个地方可以有很多post。一个post属于一个地方

我正在使用 Aqueduct 3.0 预发布版。

我有以下型号:

place.dart

class Place extends ManagedObject<_Place> implements _Place {}

class _Place {
  @primaryKey
  int id;

  @Column(unique: true)
  String name;

  ManagedSet<Post> posts;
}

post.dart

import 'package:places_api/model/place.dart';
import 'package:places_api/places_api.dart';

class Post extends ManagedObject<_Post> implements _Post {}

class _Post {
  @primaryKey
  int id;

  @Column()
  String text;

  @Relate(#posts)
  Place place;
}

我尝试保存 post,但只能保存地点对象,而不是 place_id。显然下面的 post 查询不起作用,因为只有一个 values.place 对象,而不是 values.place_id 属性。是不是要加载这个地方,然后把所有的post存进去?

同样没有关系,我无法存储 place_id,因为 Aqueduct 似乎将 _ 视为特殊的东西。我不能使用带有下划线的数据库属性吗?

有没有例子可以解释这个?

  @Operation.post()
  Future<Response> createPost() async {
    final body = request.body.asMap();
    final query = new Query<Post>(context)
      ..values.place_id = body['place_id']
      ..values.text = body['text'];

    final insertedPost = await query.insert();

    return new Response.ok(insertedPost);
  }

目前我正在发送以下正文 POST:

{
    "place_id": 1,
    "text": "My post here"
}

关注URL:http://localhost:8888/posts

发送这样的东西会更好吗?

{
    "text": "My post here"
}

至URL:http://localhost:8888/place/1/posts

然后先取地方,把post存进去?

当表示为 JSON 时,关系始终是列表或对象。在你的情况下:

{
  "text": "text",
  "place": {
    "id": 1
  }
}

这允许客户端应用程序解析代码保持一致 - 相关对象始终是对象,而不是合成字段(例如,place_id)。底层数据库确实通过使用下划线连接关系名称及其主键名称来命名列 place_id,但这是一个未通过 API.

公开的实现细节

插入对象时,会插入外键,因为它们是 table 中的一列。所以,你可以这样写你的操作方法:

@Operation.post()
Future<Response> createPost(@Bind.body() Post post) async {
  final query = new Query<Post>(context)
    ..values = post;

  final insertedPost = await query.insert();

  return new Response.ok(insertedPost);
}

如果您使用示例 JSON 和此代码,您将得到此 SQL 查询:INSERT INTO _post (text, place_id) VALUES ('text', 1).

插入关系的 'has' 端时,您必须将相关对象作为单独的查询插入。 update/insert 查询只会在单个 table 上显示 set/insert 个值。如果对你的 API 有意义,你可能想要 POST 以下位置 JSON:

{
  "name": "Place",
  "posts": [
    {"text": "text"}
  ]
}

插入此对象图的代码可能如下所示:

await context.transaction((t) async {
  final q = Query<Place>(t)..values = body;
  final insertedPlace = await q.insert();
  await Future.wait(body.posts, (p) async {
    final postQuery = Query<Post>(t)
      ..values = p
      ..values.place.id = insertedPlace.id;
    return postQuery.insert();
  });
});

一些其他小注释:asMap 已被删除并替换为 as<T>decode<T>。如果您不添加任何标志,您也不需要 @Column 注释。 table 定义类型中声明的所有字段都是数据库列。瞬态字段在 ManagedObject 子类中声明,如果您希望它们成为 API 表面的一部分,可以用 @Serialize() 注释。