Type-graphql, Mikororm Query returns Ref<User> 而不是 User
Type-graphql, Mikororm Query returns Ref<User> rather than User
我正在使用 Mikro-ORM、Type-graphql、NodeJs、Express、Redis 和 PostgreSQL 创建 Reddit 的克隆版本的项目后端
这是我使用 Mikororm 的初始项目设置,将其连接到 Postgres,并启动 Redis 进行缓存
const orm = await MikroORM.init(microConfig);
// run the Migration before do anything else
await orm.getMigrator().up();
// create an express server app
const app = express();
// set up redis running
const RedisStore = connectRedis(session);
const redis = new Redis();
app.use(
cors({
origin: "http://localhost:3000",
credentials: true,
})
);
app.use(
session({
name: COOKIE_Name,
store: new RedisStore({
client: redis,
disableTTL: true,
}),
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 365 * 3, // 3 years cookies
httpOnly: true,
secure: __prod__, // cookie only works in https
sameSite: "lax", //csrf: google this for more information
},
saveUninitialized: false,
secret: "nkadniandiuanidnaidhaiddwq",
resave: false,
})
);
app.get("/", (_, res) => {
res.send("hello");
});
app.listen(4000, () => {
console.log("server started on localhost:4000");
});
// Apollo server
const apolloServer = new ApolloServer({
schema: await buildSchema({
resolvers: [HelloResolver, PostResolver, UserResolver],
validate: false,
}),
context: ({ req, res }): MyContext => ({ em: orm.em, req, res, redis }),
});
apolloServer.applyMiddleware({
app,
cors: false,
});
};
我的实体为 Post.js
设置
@ObjectType()
@Entity()
export class Post {
@Field()
@PrimaryKey()
_id!: number;
@Field()
@Property()
creatorId!: number;
@Field()
@Property({ type: "date" })
createdAt: Date = new Date();
@Field()
@Property({ type: "date", onUpdate: () => new Date() })
updatedAt: Date = new Date();
@Field()
@Property({ type: "text" })
title!: string;
@Field()
@Property({ type: "text" })
text!: string;
@Field()
@Property({ type: "number" })
points!: number;
@Field()
@ManyToOne(() => User)
creator: User;
constructor(creator: User) {
this.creator = creator;
}
@OneToMany(() => Upvote, (upvote) => upvote.post)
upvote = new Collection<Upvote>(this);
}
和User.js
@ObjectType()
@Entity()
export class User {
@Field()
@PrimaryKey()
@Property()
_id!: number;
@Field()
@Property({ type: "date" })
createdAt: Date = new Date();
@Field()
@Property({ type: "date", onUpdate: () => new Date() })
updatedAt: Date = new Date();
@Field()
@Property({ type: "text", unique: true })
username!: string;
@Field()
@Property({ type: "text", unique: true })
email!: string;
@Property({ type: "text" })
password!: string;
@OneToMany(() => Post, (post) => post.creator)
posts = new Collection<Post>(this);
@OneToMany(() => Upvote, (upvote) => upvote.user)
upvote = new Collection<Upvote>(this);
}
这是我查询所有帖子的解析器,每个 post 都会有一个创建者(即用户),一个用户可以创建多个 post:
@Query(() => PaginatedPosts)
async posts(
@Arg("limit", () => Int) limit: number,
@Arg("cursor", () => String, { nullable: true }) cursor: string,
@Ctx() { em }: MyContext
) {
const realLimit = Math.min(50, limit);
const realLimitPlusOne = realLimit + 1;
const withCursor = await em
.getRepository(Post)
.find(
{ $and: [{ "createdAt <=": cursor }] },
{ limit: realLimitPlusOne, orderBy: { createdAt: "DESC" } }
);
const withoutCursor = await em
.getRepository(Post)
.find({}, { limit: realLimitPlusOne, orderBy: { createdAt: "DESC" } });
// console.log("Post with Cursor:", withCursor);
console.log("Post without Cursor", withoutCursor);
if (cursor) {
return {
posts: withCursor.slice(0, realLimit),
hasMore: withCursor.length === realLimitPlusOne,
};
} else {
return {
posts: withoutCursor.slice(0, realLimit),
hasMore: withoutCursor.length === realLimitPlusOne,
};
}
}
问题出现的时候是这样的,有时Datareturn对我来说只是Ref而不是我想要的User对象
Post {
_id: 214,
creatorId: 18,
createdAt: 2021-07-31T09:48:50.000Z,
updatedAt: 2021-07-31T09:48:50.000Z,
title: 'Yay It works ',
text: ':>>>',
points: 3,
creator: Ref<User> { _id: 18 },
upvote: Collection { initialized: false, dirty: false }
}
但有时它确实有效,但很多时候查询失败,因为它只是 returnRef<> 而不是整个用户对象
Post {
_id: 214,
creatorId: 18,
createdAt: 2021-07-31T09:48:50.000Z,
updatedAt: 2021-07-31T09:48:50.000Z,
title: 'Yay It works ',
text: ':>>>',
points: 3,
creator: User {
_id: 18,
createdAt: 2021-07-19T15:30:31.000Z,
updatedAt: 2021-07-21T06:55:03.000Z,
username: 'minhquan0902',
email: 'minhquan0902@gmail.com',
password: '$argon2i$v=19$m=4096,t=3,p=1$powvhc+mI4O/jmhXz807lg$oZtyE2HRW6Ei6JqPGcEDBdmEnv3D81C9lMNd5kmEKPA',
posts: [Collection],
upvote: [Collection]
},
看起来您没有在任何地方处理请求上下文,因此对所有请求重复使用相同的 EM。每个请求都需要有自己的 EM 分叉。
请参阅 https://mikro-orm.io/docs/identity-map 了解原因。
我没有使用 apollo 的经验,但我相信更改此行应该足够了:
context: ({ req, res }): MyContext => ({ em: orm.em, req, res, redis }),
使用新的 fork 而不是全局 orm.em
context: ({ req, res }): MyContext => ({ em: orm.em.fork(), req, res, redis }),
这是一个以这种方式执行的示例应用程序:
https://github.com/driescroons/mikro-orm-graphql-example/blob/master/src/application.ts#L63
我正在使用 Mikro-ORM、Type-graphql、NodeJs、Express、Redis 和 PostgreSQL 创建 Reddit 的克隆版本的项目后端
这是我使用 Mikororm 的初始项目设置,将其连接到 Postgres,并启动 Redis 进行缓存
const orm = await MikroORM.init(microConfig);
// run the Migration before do anything else
await orm.getMigrator().up();
// create an express server app
const app = express();
// set up redis running
const RedisStore = connectRedis(session);
const redis = new Redis();
app.use(
cors({
origin: "http://localhost:3000",
credentials: true,
})
);
app.use(
session({
name: COOKIE_Name,
store: new RedisStore({
client: redis,
disableTTL: true,
}),
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 365 * 3, // 3 years cookies
httpOnly: true,
secure: __prod__, // cookie only works in https
sameSite: "lax", //csrf: google this for more information
},
saveUninitialized: false,
secret: "nkadniandiuanidnaidhaiddwq",
resave: false,
})
);
app.get("/", (_, res) => {
res.send("hello");
});
app.listen(4000, () => {
console.log("server started on localhost:4000");
});
// Apollo server
const apolloServer = new ApolloServer({
schema: await buildSchema({
resolvers: [HelloResolver, PostResolver, UserResolver],
validate: false,
}),
context: ({ req, res }): MyContext => ({ em: orm.em, req, res, redis }),
});
apolloServer.applyMiddleware({
app,
cors: false,
});
};
我的实体为 Post.js
设置@ObjectType()
@Entity()
export class Post {
@Field()
@PrimaryKey()
_id!: number;
@Field()
@Property()
creatorId!: number;
@Field()
@Property({ type: "date" })
createdAt: Date = new Date();
@Field()
@Property({ type: "date", onUpdate: () => new Date() })
updatedAt: Date = new Date();
@Field()
@Property({ type: "text" })
title!: string;
@Field()
@Property({ type: "text" })
text!: string;
@Field()
@Property({ type: "number" })
points!: number;
@Field()
@ManyToOne(() => User)
creator: User;
constructor(creator: User) {
this.creator = creator;
}
@OneToMany(() => Upvote, (upvote) => upvote.post)
upvote = new Collection<Upvote>(this);
}
和User.js
@ObjectType()
@Entity()
export class User {
@Field()
@PrimaryKey()
@Property()
_id!: number;
@Field()
@Property({ type: "date" })
createdAt: Date = new Date();
@Field()
@Property({ type: "date", onUpdate: () => new Date() })
updatedAt: Date = new Date();
@Field()
@Property({ type: "text", unique: true })
username!: string;
@Field()
@Property({ type: "text", unique: true })
email!: string;
@Property({ type: "text" })
password!: string;
@OneToMany(() => Post, (post) => post.creator)
posts = new Collection<Post>(this);
@OneToMany(() => Upvote, (upvote) => upvote.user)
upvote = new Collection<Upvote>(this);
}
这是我查询所有帖子的解析器,每个 post 都会有一个创建者(即用户),一个用户可以创建多个 post:
@Query(() => PaginatedPosts)
async posts(
@Arg("limit", () => Int) limit: number,
@Arg("cursor", () => String, { nullable: true }) cursor: string,
@Ctx() { em }: MyContext
) {
const realLimit = Math.min(50, limit);
const realLimitPlusOne = realLimit + 1;
const withCursor = await em
.getRepository(Post)
.find(
{ $and: [{ "createdAt <=": cursor }] },
{ limit: realLimitPlusOne, orderBy: { createdAt: "DESC" } }
);
const withoutCursor = await em
.getRepository(Post)
.find({}, { limit: realLimitPlusOne, orderBy: { createdAt: "DESC" } });
// console.log("Post with Cursor:", withCursor);
console.log("Post without Cursor", withoutCursor);
if (cursor) {
return {
posts: withCursor.slice(0, realLimit),
hasMore: withCursor.length === realLimitPlusOne,
};
} else {
return {
posts: withoutCursor.slice(0, realLimit),
hasMore: withoutCursor.length === realLimitPlusOne,
};
}
}
问题出现的时候是这样的,有时Datareturn对我来说只是Ref而不是我想要的User对象
Post {
_id: 214,
creatorId: 18,
createdAt: 2021-07-31T09:48:50.000Z,
updatedAt: 2021-07-31T09:48:50.000Z,
title: 'Yay It works ',
text: ':>>>',
points: 3,
creator: Ref<User> { _id: 18 },
upvote: Collection { initialized: false, dirty: false }
}
但有时它确实有效,但很多时候查询失败,因为它只是 returnRef<> 而不是整个用户对象
Post {
_id: 214,
creatorId: 18,
createdAt: 2021-07-31T09:48:50.000Z,
updatedAt: 2021-07-31T09:48:50.000Z,
title: 'Yay It works ',
text: ':>>>',
points: 3,
creator: User {
_id: 18,
createdAt: 2021-07-19T15:30:31.000Z,
updatedAt: 2021-07-21T06:55:03.000Z,
username: 'minhquan0902',
email: 'minhquan0902@gmail.com',
password: '$argon2i$v=19$m=4096,t=3,p=1$powvhc+mI4O/jmhXz807lg$oZtyE2HRW6Ei6JqPGcEDBdmEnv3D81C9lMNd5kmEKPA',
posts: [Collection],
upvote: [Collection]
},
看起来您没有在任何地方处理请求上下文,因此对所有请求重复使用相同的 EM。每个请求都需要有自己的 EM 分叉。
请参阅 https://mikro-orm.io/docs/identity-map 了解原因。
我没有使用 apollo 的经验,但我相信更改此行应该足够了:
context: ({ req, res }): MyContext => ({ em: orm.em, req, res, redis }),
使用新的 fork 而不是全局 orm.em
context: ({ req, res }): MyContext => ({ em: orm.em.fork(), req, res, redis }),
这是一个以这种方式执行的示例应用程序: https://github.com/driescroons/mikro-orm-graphql-example/blob/master/src/application.ts#L63