Identity Field (Поле первичного ключа)
Паттерн проектирования Identity Field
Описание Identity Field
Хранит первичный ключ из БД в объекте, чтобы обеспечивать соответствие между объектом и строкой в БД.
Реляционные базы данных отличают одну запись от другой при помощи первичного ключа. Но объекты в памяти не нуждаются в таком ключе, так как объектная система следит отличием объектов сама. При чтении из БД проблем не возникает, но для записи, нужна привязка объектной системы к БД.
Для этого нет ничего проще и очевиднее, чем Identity Field. Всё, что нужно - это хранить первичный ключ из БД в свостве объекта
Примеры реализации
// Identity Field Pattern in JavaScript
class User {
constructor(id, name, email) {
this.id = id; // Identity Field - primary key from database
this.name = name;
this.email = email;
}
getId() {
return this.id;
}
setId(id) {
this.id = id;
}
getName() {
return this.name;
}
getEmail() {
return this.email;
}
// Method to check if object is persisted
isPersisted() {
return this.id !== null && this.id !== undefined;
}
// Method to mark as new (no ID yet)
markAsNew() {
this.id = null;
}
}
class Product {
constructor(id, name, price, categoryId) {
this.id = id; // Identity Field - primary key
this.name = name;
this.price = price;
this.categoryId = categoryId; // Foreign key reference
}
getId() {
return this.id;
}
setId(id) {
this.id = id;
}
getCategoryId() {
return this.categoryId;
}
setCategoryId(categoryId) {
this.categoryId = categoryId;
}
}
class Order {
constructor(id, userId, orderDate, totalAmount) {
this.id = id; // Identity Field
this.userId = userId; // Foreign key to User
this.orderDate = orderDate;
this.totalAmount = totalAmount;
this.items = [];
}
getId() {
return this.id;
}
getUserId() {
return this.userId;
}
addItem(productId, quantity, price) {
this.items.push({
id: null, // Will be set when saved to database
productId: productId,
quantity: quantity,
price: price
});
}
}
// Usage examples
const user = new User(1, 'John Doe', 'john@example.com');
console.log('User ID:', user.getId());
console.log('Is persisted:', user.isPersisted());
const product = new Product(101, 'Laptop', 999.99, 5);
console.log('Product ID:', product.getId());
console.log('Category ID:', product.getCategoryId());
const order = new Order(1001, 1, new Date(), 1999.98);
order.addItem(101, 1, 999.99);
order.addItem(102, 1, 999.99);
console.log('Order ID:', order.getId());
console.log('User ID:', order.getUserId());
console.log('Order items:', order.items);
// Creating new objects (no ID yet)
const newUser = new User(null, 'Jane Smith', 'jane@example.com');
newUser.markAsNew();
console.log('New user is persisted:', newUser.isPersisted());
// After saving to database, ID would be set
newUser.setId(2);
console.log('After save - User ID:', newUser.getId());
console.log('After save - Is persisted:', newUser.isPersisted());
<?php
// Identity Field Pattern in PHP
class User {
private $id; // Identity Field - primary key from database
private $name;
private $email;
public function __construct($id, $name, $email) {
$this->id = $id;
$this->name = $name;
$this->email = $email;
}
public function getId() {
return $this->id;
}
public function setId($id) {
$this->id = $id;
}
public function getName() {
return $this->name;
}
public function getEmail() {
return $this->email;
}
// Method to check if object is persisted
public function isPersisted() {
return $this->id !== null;
}
// Method to mark as new (no ID yet)
public function markAsNew() {
$this->id = null;
}
}
class Product {
private $id; // Identity Field - primary key
private $name;
private $price;
private $categoryId; // Foreign key reference
public function __construct($id, $name, $price, $categoryId) {
$this->id = $id;
$this->name = $name;
$this->price = $price;
$this->categoryId = $categoryId;
}
public function getId() {
return $this->id;
}
public function setId($id) {
$this->id = $id;
}
public function getCategoryId() {
return $this->categoryId;
}
public function setCategoryId($categoryId) {
$this->categoryId = $categoryId;
}
}
class Order {
private $id; // Identity Field
private $userId; // Foreign key to User
private $orderDate;
private $totalAmount;
private $items;
public function __construct($id, $userId, $orderDate, $totalAmount) {
$this->id = $id;
$this->userId = $userId;
$this->orderDate = $orderDate;
$this->totalAmount = $totalAmount;
$this->items = [];
}
public function getId() {
return $this->id;
}
public function getUserId() {
return $this->userId;
}
public function addItem($productId, $quantity, $price) {
$this->items[] = [
'id' => null, // Will be set when saved to database
'productId' => $productId,
'quantity' => $quantity,
'price' => $price
];
}
public function getItems() {
return $this->items;
}
}
// Usage examples
$user = new User(1, 'John Doe', 'john@example.com');
echo "User ID: " . $user->getId() . "\n";
echo "Is persisted: " . ($user->isPersisted() ? 'true' : 'false') . "\n";
$product = new Product(101, 'Laptop', 999.99, 5);
echo "Product ID: " . $product->getId() . "\n";
echo "Category ID: " . $product->getCategoryId() . "\n";
$order = new Order(1001, 1, new DateTime(), 1999.98);
$order->addItem(101, 1, 999.99);
$order->addItem(102, 1, 999.99);
echo "Order ID: " . $order->getId() . "\n";
echo "User ID: " . $order->getUserId() . "\n";
echo "Order items: " . json_encode($order->getItems()) . "\n";
// Creating new objects (no ID yet)
$newUser = new User(null, 'Jane Smith', 'jane@example.com');
$newUser->markAsNew();
echo "New user is persisted: " . ($newUser->isPersisted() ? 'true' : 'false') . "\n";
// After saving to database, ID would be set
$newUser->setId(2);
echo "After save - User ID: " . $newUser->getId() . "\n";
echo "After save - Is persisted: " . ($newUser->isPersisted() ? 'true' : 'false') . "\n";
?>
// Identity Field Pattern in Go
package main
import (
"fmt"
"time"
)
type User struct {
ID *int // Identity Field - primary key from database (pointer to allow nil)
Name string
Email string
}
func NewUser(id *int, name, email string) *User {
return &User{
ID: id,
Name: name,
Email: email,
}
}
func (u *User) GetID() *int {
return u.ID
}
func (u *User) SetID(id *int) {
u.ID = id
}
func (u *User) GetName() string {
return u.Name
}
func (u *User) GetEmail() string {
return u.Email
}
// Method to check if object is persisted
func (u *User) IsPersisted() bool {
return u.ID != nil
}
// Method to mark as new (no ID yet)
func (u *User) MarkAsNew() {
u.ID = nil
}
type Product struct {
ID *int // Identity Field - primary key
Name string
Price float64
CategoryID *int // Foreign key reference
}
func NewProduct(id *int, name string, price float64, categoryID *int) *Product {
return &Product{
ID: id,
Name: name,
Price: price,
CategoryID: categoryID,
}
}
func (p *Product) GetID() *int {
return p.ID
}
func (p *Product) SetID(id *int) {
p.ID = id
}
func (p *Product) GetCategoryID() *int {
return p.CategoryID
}
func (p *Product) SetCategoryID(categoryID *int) {
p.CategoryID = categoryID
}
type OrderItem struct {
ID *int
ProductID *int
Quantity int
Price float64
}
type Order struct {
ID *int // Identity Field
UserID *int // Foreign key to User
OrderDate time.Time
TotalAmount float64
Items []OrderItem
}
func NewOrder(id *int, userID *int, orderDate time.Time, totalAmount float64) *Order {
return &Order{
ID: id,
UserID: userID,
OrderDate: orderDate,
TotalAmount: totalAmount,
Items: make([]OrderItem, 0),
}
}
func (o *Order) GetID() *int {
return o.ID
}
func (o *Order) GetUserID() *int {
return o.UserID
}
func (o *Order) AddItem(productID *int, quantity int, price float64) {
item := OrderItem{
ID: nil, // Will be set when saved to database
ProductID: productID,
Quantity: quantity,
Price: price,
}
o.Items = append(o.Items, item)
}
func (o *Order) GetItems() []OrderItem {
return o.Items
}
func main() {
// Usage examples
userID := 1
user := NewUser(&userID, "John Doe", "john@example.com")
fmt.Printf("User ID: %d\n", *user.GetID())
fmt.Printf("Is persisted: %t\n", user.IsPersisted())
productID := 101
categoryID := 5
product := NewProduct(&productID, "Laptop", 999.99, &categoryID)
fmt.Printf("Product ID: %d\n", *product.GetID())
fmt.Printf("Category ID: %d\n", *product.GetCategoryID())
orderID := 1001
orderUserID := 1
order := NewOrder(&orderID, &orderUserID, time.Now(), 1999.98)
productID1 := 101
productID2 := 102
order.AddItem(&productID1, 1, 999.99)
order.AddItem(&productID2, 1, 999.99)
fmt.Printf("Order ID: %d\n", *order.GetID())
fmt.Printf("User ID: %d\n", *order.GetUserID())
fmt.Printf("Order items: %+v\n", order.GetItems())
// Creating new objects (no ID yet)
newUser := NewUser(nil, "Jane Smith", "jane@example.com")
newUser.MarkAsNew()
fmt.Printf("New user is persisted: %t\n", newUser.IsPersisted())
// After saving to database, ID would be set
newUserID := 2
newUser.SetID(&newUserID)
fmt.Printf("After save - User ID: %d\n", *newUser.GetID())
fmt.Printf("After save - Is persisted: %t\n", newUser.IsPersisted())
}
Использована иллюстрация с сайта Мартина Фаулера.