mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
fixed many to many when using lazy loading
This commit is contained in:
parent
60fc079f85
commit
37c2731f89
@ -1,6 +1,7 @@
|
||||
import {createConnection, CreateConnectionOptions} from "../../src/typeorm";
|
||||
import {Post} from "./entity/Post";
|
||||
import {Author} from "./entity/Author";
|
||||
import {Category} from "./entity/Category";
|
||||
|
||||
const options: CreateConnectionOptions = {
|
||||
driver: "mysql",
|
||||
@ -16,13 +17,14 @@ const options: CreateConnectionOptions = {
|
||||
logFailedQueryError: true
|
||||
}
|
||||
},
|
||||
entities: [Post, Author]
|
||||
entities: [Post, Author, Category]
|
||||
};
|
||||
|
||||
createConnection(options).then(connection => {
|
||||
|
||||
let postRepository = connection.getRepository(Post);
|
||||
let authorRepository = connection.getRepository(Author);
|
||||
let categoryRepository = connection.getRepository(Category);
|
||||
|
||||
let author = authorRepository.create();
|
||||
author.name = "Umed";
|
||||
@ -67,6 +69,40 @@ createConnection(options).then(connection => {
|
||||
})
|
||||
.then(posts => {
|
||||
console.log("Two post's author has been removed.");
|
||||
console.log("Now lets check many-to-many relations");
|
||||
|
||||
let category1 = categoryRepository.create();
|
||||
category1.name = "Hello category1";
|
||||
|
||||
let category2 = categoryRepository.create();
|
||||
category2.name = "Bye category2";
|
||||
|
||||
let post = postRepository.create();
|
||||
post.title = "Post & Categories";
|
||||
post.text = "Post with many categories";
|
||||
post.categories = Promise.resolve([
|
||||
category1,
|
||||
category2
|
||||
]);
|
||||
|
||||
return postRepository.persist(post);
|
||||
})
|
||||
.then(posts => {
|
||||
console.log("Post has been saved with its categories. ");
|
||||
console.log("Lets find it now. ");
|
||||
return postRepository.find({ alias: "post", innerJoinAndSelect: { categories: "post.categories" } });
|
||||
})
|
||||
.then(posts => {
|
||||
console.log("Post with categories are loaded: ", posts);
|
||||
console.log("Lets remove one of the categories: ");
|
||||
return posts[0].categories.then(categories => {
|
||||
categories.splice(0, 1);
|
||||
// console.log(posts[0]);
|
||||
return postRepository.persist(posts[0]);
|
||||
});
|
||||
})
|
||||
.then(posts => {
|
||||
console.log("One of the post category has been removed.");
|
||||
})
|
||||
.catch(error => console.log(error.stack));
|
||||
|
||||
|
||||
18
sample/sample18-lazy-relations/entity/Category.ts
Normal file
18
sample/sample18-lazy-relations/entity/Category.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import {PrimaryColumn, Column} from "../../../src/columns";
|
||||
import {Table} from "../../../src/tables";
|
||||
import {ManyToMany} from "../../../src/decorator/relations/ManyToMany";
|
||||
import {Post} from "./Post";
|
||||
|
||||
@Table("sample18_category")
|
||||
export class Category {
|
||||
|
||||
@PrimaryColumn("int", { generated: true })
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@ManyToMany(type => Post, post => post.categories)
|
||||
posts: Promise<Post[]>;
|
||||
|
||||
}
|
||||
@ -2,6 +2,9 @@ import {PrimaryColumn, Column} from "../../../src/columns";
|
||||
import {Table} from "../../../src/tables";
|
||||
import {Author} from "./Author";
|
||||
import {ManyToOne} from "../../../src/decorator/relations/ManyToOne";
|
||||
import {Category} from "./Category";
|
||||
import {ManyToMany} from "../../../src/decorator/relations/ManyToMany";
|
||||
import {JoinTable} from "../../../src/decorator/relations/JoinTable";
|
||||
|
||||
@Table("sample18_post")
|
||||
export class Post {
|
||||
@ -22,4 +25,10 @@ export class Post {
|
||||
})
|
||||
author: Promise<Author|null>;
|
||||
|
||||
@ManyToMany(type => Category, category => category.posts, {
|
||||
cascadeAll: true
|
||||
})
|
||||
@JoinTable()
|
||||
categories: Promise<Category[]>;
|
||||
|
||||
}
|
||||
@ -273,15 +273,19 @@ export class EntityPersistOperationBuilder {
|
||||
});
|
||||
return metadata.relations
|
||||
.filter(relation => relation.isManyToMany)
|
||||
.filter(relation => newEntity[relation.propertyName] instanceof Array)
|
||||
// .filter(relation => newEntity[relation.propertyName] instanceof Array)
|
||||
.reduce((operations, relation) => {
|
||||
const relationMetadata = relation.relatedEntityMetadata;
|
||||
const relationIdProperty = relationMetadata.primaryColumn.name;
|
||||
newEntity[relation.propertyName].map((subEntity: any) => {
|
||||
const value = this.getEntityRelationValue(relation, newEntity);
|
||||
const dbValue = dbEntity ? this.getEntityRelationValue(relation, dbEntity.entity) : null;
|
||||
|
||||
if (!(value instanceof Array))
|
||||
return operations;
|
||||
|
||||
value.forEach((subEntity: any) => {
|
||||
|
||||
const has = !dbEntity ||
|
||||
!dbEntity.entity[relation.propertyName] ||
|
||||
!dbEntity.entity[relation.propertyName].find((e: any) => e[relationIdProperty] === subEntity[relationIdProperty]);
|
||||
const has = !dbValue || !dbValue.find((e: any) => e[relationIdProperty] === subEntity[relationIdProperty]);
|
||||
|
||||
if (has) {
|
||||
operations.push({
|
||||
@ -307,15 +311,19 @@ export class EntityPersistOperationBuilder {
|
||||
});
|
||||
return metadata.relations
|
||||
.filter(relation => relation.isManyToMany)
|
||||
.filter(relation => dbEntity[relation.propertyName] instanceof Array)
|
||||
// .filter(relation => dbEntity[relation.propertyName] instanceof Array)
|
||||
.reduce((operations, relation) => {
|
||||
const relationMetadata = relation.relatedEntityMetadata;
|
||||
const relationIdProperty = relationMetadata.primaryColumn.name;
|
||||
dbEntity[relation.propertyName].map((subEntity: any) => {
|
||||
const value = newEntity ? this.getEntityRelationValue(relation, newEntity.entity) : null;
|
||||
const dbValue = this.getEntityRelationValue(relation, dbEntity);
|
||||
|
||||
const has = !newEntity ||
|
||||
!newEntity.entity[relation.propertyName] ||
|
||||
!newEntity.entity[relation.propertyName].find((e: any) => e[relationIdProperty] === subEntity[relationIdProperty]);
|
||||
if (!(dbValue instanceof Array))
|
||||
return operations;
|
||||
|
||||
dbValue.forEach((subEntity: any) => {
|
||||
|
||||
const has = !value || !value.find((e: any) => e[relationIdProperty] === subEntity[relationIdProperty]);
|
||||
|
||||
if (has) {
|
||||
operations.push({
|
||||
|
||||
@ -77,42 +77,6 @@ export class Repository<Entity> {
|
||||
return <Entity> this.addLazyProperties(this.metadata.create());
|
||||
}
|
||||
|
||||
// todo: duplication
|
||||
private addLazyProperties(entity: any) {
|
||||
const metadata = this.entityMetadatas.findByTarget(entity.constructor);
|
||||
metadata.relations
|
||||
.filter(relation => relation.isLazy)
|
||||
.forEach(relation => {
|
||||
const index = "__" + relation.propertyName + "__";
|
||||
|
||||
Object.defineProperty(entity, relation.propertyName, {
|
||||
get: () => {
|
||||
if (entity[index])
|
||||
return Promise.resolve(entity[index]);
|
||||
// find object metadata and try to load
|
||||
return new QueryBuilder(this.driver, this.entityMetadatas, this.broadcaster)
|
||||
.select(relation.propertyName)
|
||||
.from(relation.target, relation.propertyName) // todo: change `id` after join column implemented
|
||||
.where(relation.propertyName + ".id=:" + relation.propertyName + "Id")
|
||||
.setParameter(relation.propertyName + "Id", entity[index])
|
||||
.getSingleResult()
|
||||
.then(result => {
|
||||
entity[index] = result;
|
||||
return entity[index];
|
||||
});
|
||||
},
|
||||
set: (promise: Promise<any>) => {
|
||||
if (promise instanceof Promise) {
|
||||
promise.then(result => entity[index] = result);
|
||||
} else {
|
||||
entity[index] = promise;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates entities from a given array of plain javascript objects.
|
||||
*/
|
||||
@ -412,4 +376,40 @@ export class Repository<Entity> {
|
||||
});
|
||||
}
|
||||
|
||||
// todo: duplication
|
||||
private addLazyProperties(entity: any) {
|
||||
const metadata = this.entityMetadatas.findByTarget(entity.constructor);
|
||||
metadata.relations
|
||||
.filter(relation => relation.isLazy)
|
||||
.forEach(relation => {
|
||||
const index = "__" + relation.propertyName + "__";
|
||||
|
||||
Object.defineProperty(entity, relation.propertyName, {
|
||||
get: () => {
|
||||
if (entity[index])
|
||||
return Promise.resolve(entity[index]);
|
||||
// find object metadata and try to load
|
||||
return new QueryBuilder(this.driver, this.entityMetadatas, this.broadcaster)
|
||||
.select(relation.propertyName)
|
||||
.from(relation.target, relation.propertyName) // todo: change `id` after join column implemented
|
||||
.where(relation.propertyName + ".id=:" + relation.propertyName + "Id")
|
||||
.setParameter(relation.propertyName + "Id", entity[index])
|
||||
.getSingleResult()
|
||||
.then(result => {
|
||||
entity[index] = result;
|
||||
return entity[index];
|
||||
});
|
||||
},
|
||||
set: (promise: Promise<any>) => {
|
||||
if (promise instanceof Promise) {
|
||||
promise.then(result => entity[index] = result);
|
||||
} else {
|
||||
entity[index] = promise;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
return entity;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user