CRUD-operaatiot TypeORMilla
Kehittäkää entiteeteille täydet Create-, Read-, Update- ja Delete-toiminnot TypeORM-repositoryjen avulla.
CRUD-operaatiot TypeORMilla on ilmainen NestJS-yritysbackendien API:t-oppitunti CoddyKitissä. Tämä on oppitunti 2/3. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu NestJS-yritysbackendien API:t-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. NestJS-yritysbackendien API:t-kurssilla on yhteensä 3 oppituntia.
CRUD-perusteet TypeORMilla
Tervetuloa! Tässä oppitunnissa opitte hallitsemaan CRUD-toimintoja TypeORMilla, joka on tehokas TypeScriptin Object-Relational Mapper.
CRUD tulee sanoista Create, Read, Update ja Delete. Nämä ovat tietojen hallinnan neljä perustoimintoa lähes kaikissa sovelluksissa.
TypeORM helpottaa tietokannan käsittelyä yhdistämällä tietokantarivit TypeScript-olioihin, mikä tekee näistä toiminnoista intuitiivisia.
Product-entiteetin määrittäminen
Ennen CRUD-toimintojen suorittamista tarvitsemme entiteetin. Entiteetti on luokka, joka vastaa suoraan tietokantataulua. Kuvitellaan esimerkkejämme varten yksinkertainen Product-entiteetti.
TypeORMissa sen rakenne ja vastaavuus tietokantaskeemaan määritetään esimerkiksi dekoraattoreilla @Entity(), @PrimaryGeneratedColumn() ja @Column().
Repositoryn ymmärtäminen
TypeORM käyttää repository-mallia. Repository on erikoistunut kokoelma, joka huolehtii tietyn entiteetin tietojen käytöstä (esimerkiksi ProductRepository Product-entiteeteille).
Repository injektoidaan palveluihin, ja sen metodeilla suoritetaan CRUD-toimintoja. Se piilottaa monimutkaiset tietokantakyselyt.
Luo: uusien tuotteiden lisääminen
Kun tietokantaan lisätään uusia tietoja, käytetään ensisijaisesti repon .save()-metodia. Se käsittelee älykkäästi sekä uudet lisäykset että olemassa olevien entiteettien päivitykset.
Tässä on yksinkertaistettu esimerkki uuden tuotteen luomisesta:
class Product {
id: number;
name: string;
price: number;
constructor(name: string, price: number, id: number = 0) {
this.id = id;
this.name = name;
this.price = price;
}
}
class MockProductRepository {
private products: Product[] = [];
private nextId = 1;
async save(product: Product): Promise<Product> {
if (product.id === 0) { // Simulate new product
product.id = this.nextId++;
this.products.push(product);
} else { // Simulate update
const index = this.products.findIndex(p => p.id === product.id);
if (index > -1) { this.products[index] = product; }
}
return product;
}
async find(): Promise<Product[]> {
return this.products;
}
}
async function main() {
const repo = new MockProductRepository();
console.log("--- Creating a Product ---");
const newProduct = await repo.save(new Product("Keyboard", 75));
console.log("Created:", newProduct);
console.log("\n--- Current Products ---");
const allProducts = await repo.find();
console.log(allProducts);
}
main();Lue: tuotteiden hakeminen
Tietojen lukeminen on olennainen toiminto. TypeORM-repositoryt tarjoavat useita metodeja entiteettien hakemiseen:
.find(): hakee kaikki annetut ehdot täyttävät entiteetit..findOneBy(): hakee yhden entiteetin yksinkertaisen ehdon perusteella (esimerkiksi tunnuksen perusteella)..findBy(): hakee useita entiteettejä yksinkertaisten ehtojen perusteella.
Katsotaan, miten tuotteita haetaan:
class Product {
id: number;
name: string;
price: number;
constructor(name: string, price: number, id: number = 0) {
this.id = id;
this.name = name;
this.price = price;
}
}
class MockProductRepository {
private products: Product[] = [];
private nextId = 1;
async save(product: Product): Promise<Product> {
if (product.id === 0) { product.id = this.nextId++; this.products.push(product); }
else { const index = this.products.findIndex(p => p.id === product.id);
if (index > -1) { this.products[index] = product; } }
return product;
}
async find(): Promise<Product[]> { return this.products; }
async findOneBy(criteria: Partial<Product>): Promise<Product | undefined> {
return this.products.find(p =>
Object.keys(criteria).every(key => p[key as keyof Product] === criteria[key as keyof Product])
);
}
}
async function main() {
const repo = new MockProductRepository();
const product1 = await repo.save(new Product("Mouse", 25));
const product2 = await repo.save(new Product("Monitor", 300));
console.log("--- Finding All Products ---");
let allProducts = await repo.find();
console.log("All:", allProducts);
console.log("\n--- Finding One Product by ID ---");
const foundProduct = await repo.findOneBy({ id: product1.id });
console.log("Found by ID:", foundProduct);
console.log("\n--- Finding One Product by Name ---");
const namedProduct = await repo.findOneBy({ name: "Monitor" });
console.log("Found by Name:", namedProduct);
}
main();Päivitä: tuotetietojen muokkaaminen
Olemassa olevien tietojen muokkaamiseen on kaksi pääasiallista tapaa:
- Hae, muokkaa, tallenna: Hae entiteetti, päivitä sen ominaisuudet ja kutsu sitten muokatun entiteetin
.save()-metodia. - Suora päivitys: Käytä
.update(criteria, partialEntity)-metodia päivittääksesi tiettyjä sarakkeita ehdot täyttävistä entiteeteistä lataamatta niitä ensin muistiin. Tämä on tehokkaampaa suurissa päivityksissä.
class Product {
id: number;
name: string;
price: number;
constructor(name: string, price: number, id: number = 0) {
this.id = id;
this.name = name;
this.price = price;
}
}
class MockProductRepository {
private products: Product[] = [];
private nextId = 1;
async save(product: Product): Promise<Product> {
if (product.id === 0) { product.id = this.nextId++; this.products.push(product); }
else { const index = this.products.findIndex(p => p.id === product.id);
if (index > -1) { this.products[index] = product; } }
return product;
}
async findOneBy(criteria: Partial<Product>): Promise<Product | undefined> {
return this.products.find(p =>
Object.keys(criteria).every(key => p[key as keyof Product] === criteria[key as keyof Product])
);
}
async update(id: number, partialEntity: Partial<Product>): Promise<void> {
const index = this.products.findIndex(p => p.id === id);
if (index > -1) {
this.products[index] = { ...this.products[index], ...partialEntity };
}
}
}
async function main() {
const repo = new MockProductRepository();
const product = await repo.save(new Product("Headphones", 150));
console.log("Initial product:", product);
console.log("\n--- Updating Product Price ---");
let fetchedProduct = await repo.findOneBy({ id: product.id });
if (fetchedProduct) {
fetchedProduct.price = 140;
await repo.save(fetchedProduct);
}
console.log("Updated via save:", await repo.findOneBy({ id: product.id }));
const product2 = await repo.save(new Product("Webcam", 80));
console.log("Initial product 2:", product2);
await repo.update(product2.id, { price: 70, name: "HD Webcam" });
console.log("Updated via update:", await repo.findOneBy({ id: product2.id }));
}
main();Poista: tuotteiden poistaminen
Entiteettien poistamiseen tietokannasta TypeORM tarjoaa metodit .delete() ja .remove():
.delete(criteria): poistaa entiteettejä tunnuksen tai tiettyjen ehtojen perusteella. Se on tehokas, koska entiteettejä ei ensin ladata muistiin..remove(entityOrEntities): poistaa entiteettejä, jotka on jo ladattu muistiin (eli käytettävissä on koko entiteettiolio).
Poistetaan tuote esimerkkitietokannastamme:
class Product {
id: number;
name: string;
price: number;
constructor(name: string, price: number, id: number = 0) {
this.id = id;
this.name = name;
this.price = price;
}
}
class MockProductRepository {
private products: Product[] = [];
private nextId = 1;
async save(product: Product): Promise<Product> {
if (product.id === 0) { product.id = this.nextId++; this.products.push(product); }
else { const index = this.products.findIndex(p => p.id === product.id);
if (index > -1) { this.products[index] = product; } }
return product;
}
async find(): Promise<Product[]> { return this.products; }
async delete(id: number): Promise<void> {
this.products = this.products.filter(p => p.id !== id);
}
async remove(product: Product): Promise<Product> {
this.products = this.products.filter(p => p.id !== product.id);
return product;
}
}
async function main() {
const repo = new MockProductRepository();
const productA = await repo.save(new Product("Pen", 2));
const productB = await repo.save(new Product("Notebook", 5));
console.log("Initial products:", await repo.find());
console.log("\n--- Deleting Product A by ID ---");
await repo.delete(productA.id);
console.log("Products after delete:", await repo.find());
console.log("\n--- Removing Product B (by entity) ---");
await repo.remove(productB);
console.log("Products after remove:", await repo.find());
}
main();CRUD NestJS-palvelussa
Oikeassa NestJS-sovelluksessa nämä repository-metodit integroitaisiin palveluun. Palvelu tarjoaisi korkeamman tason metodeja, jotka toteuttavat tietyn liiketoimintalogiikan ja kutsuvat taustalla olevia repository-metodeja.
Näin ohjaimet pysyvät selkeinä: ne keskittyvät HTTP-pyyntöjen käsittelyyn ja delegoivat tietokantaoperaatiot palvelukerrokselle.
// products.service.ts (simplified NestJS service)
import { Injectable } from '@nestjs/common';
import { Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { Product } from './product.entity'; // Your entity
@Injectable()
export class ProductsService {
constructor(
@InjectRepository(Product)
private productsRepository: Repository<Product>,
) {}
async create(productData: Partial<Product>): Promise<Product> {
const newProduct = this.productsRepository.create(productData);
return this.productsRepository.save(newProduct);
}
async findAll(): Promise<Product[]> {
return this.productsRepository.find();
}
async findOne(id: number): Promise<Product | undefined> {
return this.productsRepository.findOneBy({ id });
}
async update(id: number, productData: Partial<Product>): Promise<Product | undefined> {
await this.productsRepository.update(id, productData);
return this.findOne(id);
}
async remove(id: number): Promise<void> {
await this.productsRepository.delete(id);
}
}Vankka CRUD: parhaat käytännöt
Vankkojen CRUD-toimintojen rakentaminen edellyttää muutakin kuin repository-metodien kutsumista:
- Tietojen validointi: Käyttäkää Data Transfer Objecteja (DTO) ja validointiputkia varmistaaksenne saapuvien tietojen kelvollisuuden (käsitellään osiossa A2 L2).
- Virheenkäsittely: Käsitelkää hallitusti esimerkiksi tilanne, jossa entiteettiä ei löydy, heittämällä asianmukaisia poikkeuksia (kuten NestJS:n
NotFoundException). - Transaktiot: Käyttäkää useita tietokantamuutoksia sisältävissä monimutkaisissa toiminnoissa transaktioita (käsitellään osiossa C1 L2) tietojen yhdenmukaisuuden varmistamiseksi.
CRUD-toimintojen tietovisa
Mitä TypeORM-repositoryn metodia käytetään tyypillisesti vain tiettyjen entiteetin kenttien päivittämiseen ilman, että koko entiteetti ladataan ensin muistiin?
Kertaus: CRUD-toimintojen hallinta
Hienoa työtä! Olet oppinut TypeORM-repositoryjen CRUD-toimintojen perusteet.
- Luo: Lisää uusia entiteettejä käyttämällä
.save()-metodia. - Lue: Hae entiteettejä käyttämällä metodeja
.find()ja.findOneBy(). - Päivitä: Muokkaa entiteettiä ja käytä
.save()-metodia tai käytä osittaisiin päivityksiin.update()-metodia. - Poista: Poista entiteettejä käyttämällä metodeja
.delete()tai.remove().
Nämä taidot ovat olennaisia rakennettaessa tietopohjaisia API-rajapintoja NestJS:llä ja TypeORMilla. Seuraavaksi tutustumme virheenkäsittelyyn ja interceptoreihin, joiden avulla API-rajapinnoista tehdään entistä vankempia!
Opi TypeScript tekoälytuutorin avulla — ilmaiseksi
Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.
- Kurssit
- 20
- Oppitunnit
- 76
Usein kysytyt kysymykset
Onko oppitunti ”CRUD-operaatiot TypeORMilla” ilmainen?
Kyllä – oppitunnin ”CRUD-operaatiot TypeORMilla” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko NestJS-yritysbackendien API:t-kurssin, päivitä CoddyKit PROhon. NestJS-yritysbackendien API:t-kurssilla on yhteensä 3 oppituntia.
Mitä opin oppitunnilla ”CRUD-operaatiot TypeORMilla”?
Kehittäkää entiteeteille täydet Create-, Read-, Update- ja Delete-toiminnot TypeORM-repositoryjen avulla. Harjoittelet NestJS-yritysbackendien API:t-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.
Tarvitsenko kokemusta aloittaakseni NestJS-yritysbackendien API:t-opiskelun?
Aiempi kokemus ei ole tarpeen. CoddyKitin NestJS-yritysbackendien API:t-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 2/3.
Kuinka kauan ”CRUD-operaatiot TypeORMilla”-oppitunnin suorittaminen kestää?
Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.
Voinko kirjoittaa ja suorittaa koodia tällä NestJS-yritysbackendien API:t-oppitunnilla?
Kyllä. Jokainen NestJS-yritysbackendien API:t-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.
Kaikki tämän kurssin oppitunnit
- Reitit ja pyyntöjen käsittely
- CRUD-operaatiot TypeORMilla
- Virheenkäsittely ja interceptorit