جاوا و تکنولوژی های آن

java programming language

در این وبلاگ به بررسی نکات موجود در جاوا و تکنولوژی های آن می پردازیم

طبقه بندی موضوعی


در نگاه اول کاربرد استفاده از Annotation های NotNull@ و (Column(nullable = false@ یکسان بنظر می آیند و میتوان بجای یکدیگر استفاده شوند ولی اینگونه نیست.

حتی هنگام استفاده در یک JPA Entity  هر دو annotation از ذخیره مقادیر Null در دیتابیس جلوگیری میکند ولی تفاوت های چشمگیری دارند که در ادامه به آنها میپردازیم 



Entity نمونه :


@Entity
public class Item {
 
    @Id
    @GeneratedValue
    private Long id;
 
    private BigDecimal price;
}






NotNull@:


این annotation برای Bean Validation تعریف شده است و استفاده از آن فقط در کلاس Entity محدود نشده است 


بیاییم یکی از فیلد های Entity را NotNull@ کنیم :

@Entity
public class Item {
 
    @Id
    @GeneratedValue
    private Long id;
 
    @NotNull
    private BigDecimal price;
}


و سعی کنیم یک Entity با مقدار Null برای فیلد NotNull@ شده ذخیره کنیم :


@SpringBootTest
public class ItemIntegrationTest {
 
    @Autowired
    private ItemRepository itemRepository;
 
    @Test
    public void shouldNotAllowToPersistNullItemsPrice() {
        itemRepository.save(new Item());
    }
}


و خروجی هایبرنیت اینگونه خواهد بود :


2019-11-14 12:31:15.070 ERROR 10980 --- [ main] o.h.i.ExceptionMapperStandardImpl : 
HHH000346: Error during managed flush [Validation failed for classes 
[com.baeldung.h2db.springboot.models.Item] during persist time for groups
[javax.validation.groups.Default,] List of constraint violations:[
ConstraintViolationImpl{interpolatedMessage='must not be null', propertyPath=price, rootBeanClass=class 
com.baeldung.h2db.springboot.models.Item, 
messageTemplate='{javax.validation.constraints.NotNull.message}'}]]
  
(...)
  
Caused by: javax.validation.ConstraintViolationException: Validation failed for classes 
[com.baeldung.h2db.springboot.models.Item] during persist time for groups
[javax.validation.groups.Default,] List of constraint violations:[
ConstraintViolationImpl{interpolatedMessage='must not be null', propertyPath=price, rootBeanClass=class 
com.baeldung.h2db.springboot.models.Item, 
messageTemplate='{javax.validation.constraints.NotNull.message}'}]




همانطور که میبینید خطای javax.validation.ConstraintViolationException پرتاب شده 


** نکته قابل توجه این است که Hibernate دیتا را چون Validate نشده ذخیره نکرده است و مراحل اعتبار سنجی قبل از کوئری SQL انجام و خطا پرتاب شده است 





ساخت Schema :


وقتی هایبرنیت میخواهد اسکیمای دیتابیس را بسازد نیاز داریم که تنظیماتی را ست کنیم :


در application.properties :


spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.show-sql=true


بعد از استارت شدن برنامه، عبارت زیر در کنسول قابل مشاهده است :


create table item (
   id bigint not null,
    price decimal(19,2) not null,
    primary key (id)
)



میبینیم که عبارت not null برای column در نظر گرفته شده است چون از نظر هایبرنیت در یک کلاس Entity وقتی فیلدی NotNull@ باشد اینطور برداشت میکند که ما میخواهیم آن فیلد در دیتابیس هم Not Null باشد 

اگر بخواهیم هایبرنیت برای فیلد های NotNull@ تصمیم نگیرد کافی است عبارت hibernate.validator.apply_to_ddl را false کنیم به این صورت :


spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.validator.apply_to_ddl=false


و لاگ آن :


create table item (
   id bigint not null,
    price decimal(19,2),
    primary key (id)
)


که دیگر آن فیلد Not Null نیست







(Column(nullable = false@ :


این annotation در Java Persistence API تعریف شده است که کاربردش در استفاده در عبارات DDL برای ساخت Database Schema است 


حال بیاییم Entity را با این annotation در نظر بگیریم :

@Entity
public class Item {
 
    @Id
    @GeneratedValue
    private Long id;
 
    @Column(nullable = false)
    private BigDecimal price;
}


و سعی میکنیم این Entity را با مقدار Null برای price ذخیره کنیم :

@SpringBootTest
public class ItemIntegrationTest {
 
    @Autowired
    private ItemRepository itemRepository;
 
    @Test
    public void shouldNotAllowToPersistNullItemsPrice() {
        itemRepository.save(new Item());
    }
}


خروجی لاگ برای ساخت دیتابیس همراه با عبارت not null برای فیلد price :

Hibernate: 
     
    create table item (
       id bigint not null,
        price decimal(19,2) not null,
        primary key (id)
    )



نتیجه کوئری :


Hibernate: 
    insert 
    into
        item
        (price, id) 
    values
        (?, ?)
2019-11-14 13:23:03.000  WARN 14580 --- [main] o.h.engine.jdbc.spi.SqlExceptionHelper   : 
SQL Error: 23502, SQLState: 23502
2019-11-14 13:23:03.000 ERROR 14580 --- [main] o.h.engine.jdbc.spi.SqlExceptionHelper   : 
NULL not allowed for column "PRICE"


همانطور که مشاهده میکنیم کوئری insert ساخته شده و پیام خطا از سمت دیتابیس ارسال شده است و این یعنی کوئری در دیتابیس اجرا شده و بدون اینکه در سمت کد ما null نبودن فیلد تست شود دیتابیس جلوی ذخیره شدن آن را گرفته است و کوئری به دیتابیس ارسال شده است 





اعتبار سنجی :



اکثر منابع استفاده از (Column(nullable = false@  را برای عبارات DDL در نظر میگیرند ولی هایبرنیت قادر است فیلد های مشخص شده با (Column(nullable = false@  را اعتبار سنجی کند و برای فعال شدن این ویژگی نیاز است مقدار hibernate.check_nullability را true کنیم :


spring.jpa.show-sql=true
spring.jpa.properties.hibernate.check_nullability=true


و اگر دوباره کد قبل از اجرا کنیم میتوانیم ببینیم که قبل از ارسال کوئری به دیتابیس اعتبار سنجی صورت میگیرد :


org.springframework.dao.DataIntegrityViolationException: 
not-null property references a null or transient value : com.baeldung.h2db.springboot.models.Item.price; 
nested exception is org.hibernate.PropertyValueException: 
not-null property references a null or transient value : com.baeldung.h2db.springboot.models.Item.price


و در صورت نا معتبر بودن خطای org.hibernate.PropertyValueException پرتاب خواهد شد 










نظرات  (۰)

هیچ نظری هنوز ثبت نشده است

ارسال نظر

ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">
تجدید کد امنیتی