C# MongoDB MongoDB Driver를 구식 버전에서 업그레이드 함에 따라 변경된 문법을 정리.

 

 

MongoClient

// Old
MongoClient client = new MongoClient("CONNECTION_STRING");
// New: Same syntax.
MongoClient client = new MongoClient("CONNECTION_STRING");

 

 

MongoServer

//Old
MongoServer server = client.GetServer();
//New: MondoServer is deprecated.

 

 

MongoDatabase

// Old
MongoDatabase db = server.GetDatabase("DATABASE_NAME");
// New
IMongoDatabase db = client.GetDatabase("DATABASE_NAME");

 

 

Run Ping

// Old
db.RunCommand("ping");
// New
db.RunCommand<BsonDocument>("{'ping': 1}");

 

 

MongoCollection

// Old
MongoCollection mongoCollection = mongoDatabase.GetCollection<YourDocumentClass>("COLLECTION NAME");
// New
IMongoCollection<YourDocumentClass> mongoCollection = mongoDatabase.GetCollection<YourDocumentClass>("COLLECTION NAME");

 

 

Check the collection is exists

// Old
mongoCollection.Exists();
// New
if(mongoCollection != null)  {}

 

 

Check the index is exists

// Old
mongoCollection.IndexExistsByName(collectionIndex);
// New
listIndexes.SelectMany(idx => idx.Elements).Where(elem => elem.Name.Contains("name")).Select(name => name.Value.ToString()).Contains("INDEX_NAME");

 

 

Create a new index

// Old
IndexKeysBuilder<YourDocumentClass> keys = IndexKeys<YourDocumentClass>.Ascending(x => x.f1).Descending(x => x.f2);
IndexOptionsBuilder options = IndexOptions.SetName("INDEX_NAME");
mongoCollection.CreateIndex(keys, options);
// New
CreateIndexModel<YourDocumentClass> indexModel = new CreateIndexModel<YourDocumentClass>( 
    Builders<YourDocumentClass>.IndexKeys.Ascending(x => x.f1).Descending(x => x.f2),
    new CreateIndexOptions(){ Name: "INDEX_NAME"})
);
mongoCollection.Indexes.CreateOne(indexModel);

 

 

Find Query - FindOne

// Old
var findQuery = Query<YourDocumentClass>.EQ(x => x.f1, "VALUE");
YourDocumentClass doc = collection.FindOneAs<YourDocumentClass>(findQuery);
// New
var findQuery = Builders<YourDocumentClass>.Filter.Eq(x => x.f1, "VALUE");
List<YourDocumentClass> listYourDocumentClass = collection.Find(findQuery).Limit(1).ToList();
YourDocumentClass doc = listYourDocumentClass[0];

 

 

Update Query

// Old
var updateValues = Update<YourDocumentClass>.Set(x => x.f1, "VALUE");
WriteConcernResult result = collection.Update(findQuery, updateValues, UpdateFlags.Multi)
// New
var updateQuery = Builders<YourDocumentClass>.Update.Set(x => x.f1, "VALUE");
collection.UpdateMany(findQuery, updateQuery);

 

 

Delete Query

// Old
var query = Query<YourDocumentClass>.EQ(x => x.f1, "VALUE");
collection.Remove(query);
// New
var findQuery = Builders<YourDocumentClass>.Filter.Eq(x => x.f1, "VALUE");
collection.DeleteMany(findQuery);

 

 

Insert Query

// Old
collection.Insert(YourDocumentClass);
// New
collection.InsertOne(YourDocumentClass);

 

 

 

 

 

 

반응형

 

Windows에서 Git 사용 시 Fatal: unsafe repository. is owned by someone else. 에러 해결 방법에 대해 알아봅니다.

 

 

 

1. 현상

 

Windows OS에서 Git 사용 시 다음과 같은 에러가 발생합니다.

 

 

Fatal: unsafe repository. ...is owned by someone else. To add an exception for this directory call:...

 

 

 

2. 원인

 

Git에서 보안 취약점이 발표되었습니다. 자세한 내용은 다음 글을 참조해 주세요: Git security vulnerability announced

 

Git security vulnerability announced | The GitHub Blog

Upgrade your local installation of Git, especially if you are using Git for Windows, or you use Git on a multi-user machine.

github.blog

 

 

 

3. 수정.

 

우선 Git을 업데이트하고 다음 명령어를 통해 해당 폴더를 안전한 폴더로 지정합니다.

 

git config --global --add safe.directory {YOUR_DERECTORY_HERE}

 

 

 

4. 테스트

 

이제 Repository를 조회해 정상적으로 보이는지 확인합니다.

 

 

** 만약 동일한 오류가 계속 반복된다면 Backslash(\) 대신 Slash(/)를 사용해 경로를 지정해 보시기 바랍니다.

 

 

 

반응형

 

The server's host key is not cached. You have no guarantee that the server is the computer you think it is. 문제가 발생한 경우 해결 방법을 알아봅니다.

 

 

 

1. 현상

 

Bitbucket을 사용하기 위해 SourceTree로 Repository에 연결하면 다음과 같은 에러가 발생합니다.

 

 

Command: git -c diff.mnemonicprefix=false -c core.quotepath=false --no-optional-locks ls-remote 


출력: 
오류: The server's host key is not cached. You have no guarantee that the server is the computer you think it is.
The server's rsa2 key fingerprint is: 
If you trust this host, enter "y" to add the key to PuTTY's cache and carry on connecting.
If you want to carry on connecting just once, without adding the key to the cache, enter "n".
If you do not trust this host, press Return to abandon the connection.
Store key in cache? (y/n, Return cancels connection, i for more info) fatal: Could not read from remote repository.

Please make sure you have the correct access rights and the repository exists.

 

 

2. 수정

 

호스트의 키를 캐시 해야 합니다. putty의 plink.exe를 실행시켜 호스트를 캐시 해줍니다.

 

 

 

 

3. 테스트

 

이제 정상적으로 Repository에 접근할 수 있습니다.

 

 

 

 

 

 

반응형

 

SSH 연결 시 UNPROTECTED PRIVATE KEY FILE 에러 해결 방법에 대해 알아봅니다.

 

 

 

1. 현상

 

AWS에서 생성한 키 파일을 사용해 ssh 연결을 시도할 때 UNPROTECTED PRIVATE KEY FILE에러와 함께 접속에 실패하는 현상.

 

 

 

 

2. 수정

 

pem 파일의 권한을 수정해줘야 합니다. 다음과 같이 권한을 수정합니다.

 

 

이후 사용자 유저 하나만 추가해 다음과 같이 만듭니다.

 

 

 

 

3. 접속 테스트

 

이제 다시 접속을 시도해 봅니다.

 

 

정상적으로 접속이 되는 것을 확인할 수 있습니다.

 

 

 

 

 

반응형

 

Entity Framework를 사용해 JOIN 쿼리문을 수행하는 방법에 대해 알아봅니다.

 

 

 

0. 소스코드

 

소스코드는 다음 링크에서 확인할 수 있습니다: https://github.com/smoh-dev/EF_Join

 

GitHub - smoh-dev/EF_Join: https://smoh.tistory.com/471

https://smoh.tistory.com/471. Contribute to smoh-dev/EF_Join development by creating an account on GitHub.

github.com

 

 

 

1. DB 준비

 

MySQL을 설치 한 뒤 다음과 같은 쿼리문을 수행해 테이블을 생성합니다.

 

#Create user table
CREATE TABLE `dev_db`.`tbl_user` (
  `key` INT NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(64) NULL,
  PRIMARY KEY (`key`));

#Create order table.
CREATE TABLE `dev_db`.`tbl_order` (
  `key` INT NOT NULL AUTO_INCREMENT,
  `user_key` INT NOT NULL,
  `code` VARCHAR(128) NOT NULL,
  PRIMARY KEY (`key`),
  INDEX `fk_user_key_idx` (`user_key` ASC),
  CONSTRAINT `fk_user_key`
    FOREIGN KEY (`user_key`)
    REFERENCES `dev_db`.`tbl_user` (`key`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION);

#Insert default data.
INSERT INTO `dev_db`.`tbl_user`(`name`) VALUES ('smoh');
INSERT INTO `dev_db`.`tbl_order`(`user_key`, `code`) VALUES (1, 'my-custom-order-id');

 

 

 

 

2. 프로젝트 생성.

 

편의를 위해 간단한 프로젝트를 생성합니다.

 

 

 

 

 

3. NuGet 패키지 설치.

 

다음 NuGet 패키지를 설치합니다.

 

 

 

 

4. Table Model 생성

 

앞서 생성한 테이블대로 모델을 생성합니다.

 

//TableUser
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace my_test_api.Model
{
    [Table("tbl_user")]
    public class TableUser
    {
        [Key]
        [Column("key")]
        public int Key { get; set; }
        [Column("name")]
        public string Name { get; set; }
    }
}

//TableOrder
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace my_test_api.Model
{
    [Table("tbl_order")]
    public class TableOrder
    {
        [Key]
        [Column("key")]
        public int Key { get; set; }
        [Column("user_key")]
        public int UserKey { get; set; }
        [Column("code")]
        public string Code { get; set; }
    }
}

 

 

 

5. DB Context 생성

 

이제 DB Context를 생성해 서비스에 연결합니다.

 

//DBContext
using Microsoft.EntityFrameworkCore;
using my_test_api.Model;
namespace my_test_api
{
    public class DBContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder options)
        {
            var connectionString = "server=localhost; database=dev_db; user=dev; password=devpass";
            options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString));
        }
        public DbSet<TableUser> User { get; set; }
        public DbSet<TableOrder> Order { get; set; }
    }
}

 

//Program.cs
using my_test_api;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

//Add DBContext
builder.Services.AddSingleton<DBContext>();

var app = builder.Build();
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}
app.UseAuthorization();
app.MapControllers();
app.Run();

 

 

 

6. 컨트롤러 작성

 

다음 코드와 같이 간단한 컨트롤러를 작성합니다.

 

//UserOrderController.cs
using Microsoft.AspNetCore.Mvc;
using my_test_api.Model;
namespace my_test_api.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class UserOrderController : ControllerBase
    {
        DBContext dbContext;
        public UserOrderController(DBContext dBContext)
        {
            this.dbContext = dBContext;
        }
        // GET api/<UserOrderController>/1
        [HttpGet("{id}")]
        public string Get(int id)
        {
            var query = (from u in dbContext.Set<TableUser>()
                        join o in dbContext.Set<TableOrder>()
                        on u.Key equals o.UserKey
                        where u.Key == id
                        select new { u, o }).SingleOrDefault();
            string result = $"UserKey: {query.u.Key}, UserName: {query.u.Name}, OrderKey: {query.u.Key}, OrderCode: {query.o.Code}";
            return result;
        }
    }
}

 

내부의 query를 통해 DB Table Join 작업을 수행합니다.

 

 

 

7. 테스트

 

이제 Swagger를 열고 테스트를 진행해 봅시다.

 

 

쿼리가 정상적으로 동작해 데이터가 출력되는 것을 확인할 수 있습니다.

 

 

 

 

 

반응형

 

 

dotNet 6.0 프로젝트에서 EntityFramework를 사용해 MariaDB에 연결하는 방법에 대해 알아봅니다.

 

 

 

1. NuGet 패키지 설치.

 

다음 NuGet 패키지를 설치합니다.

 

 

 

 

2. DB 테이블 생성

 

DB에 접속해 다음 예시와 같이 테이블을 생성합니다.

 

CREATE TABLE `dev_db`.`users` (
  `Key` INT NOT NULL AUTO_INCREMENT,
  `Id` VARCHAR(128) NOT NULL,
  `Name` VARCHAR(64) NOT NULL,
  PRIMARY KEY (`Key`),
  UNIQUE INDEX `Key_UNIQUE` (`Key` ASC) VISIBLE,
  UNIQUE INDEX `Id_UNIQUE` (`Id` ASC) VISIBLE);

 

 

 

3. DBContext 생성

 

다음 예시와 같이 Model과 DbContext를 생성합니다.

 

//Model: User
    public class User
    {
        public string Id { get; set; }
        public string Name { get; set; }
        public User(string id, string name)
        {
            this.Id = id;
            this.Name = name;
        }
    }
//DbContext: UserContext
    public class UserContext : DbContext
    {
        public DbSet<User> Users { get; set; }
        protected override void OnConfiguring(DbContextOptionsBuilder options)
        {
            var connectionString = "server=localhost; database=dev_db; user=dev; password=devpass"; 
            options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString));
        }
    }

 

 

 

4. User 추가

 

다음 예시 코드를 실행해 Users 테이블에 User를 추가합니다.

 

// Insert a new user to users table.
using (var context = new UserContext())
{
    context.Users.Add(new User("testID", "testName"));
    context.SaveChanges();
}

 

 

DB에 정상적으로 데이터가 추가된 것을 확인할 수 있습니다.

 

 

 

 

 

반응형

 

 

Gradle 빌드시 Cannot find symbol 오류가 발생하는 원인에 대해 알아봅니다.

** Actual and formal argument lists differ in length 오류도 동일한 원인입니다.

 

 

 

1. 현상.

 

일반적으로 Gradle을 빌드 시스템으로 채용해도 추가 라이브러리는 Maven Repository에서 검색해 추가하게 됩니다. 이제 여기서 Lombok을 검색해 build.gradle에 추가해 봅시다.

 

 

 

이제 빌드를 하면 오류가 발생합니다.

 

 

 

 

2. 수정.

 

먼저 IntelliJ 설정에서 Enable Annotation Processor 항목을 활성화합니다.

 

 

다음으로 build.gradle로 이동해 Lombok에 annotationProcessor 항목을 추가합니다.

 

 

이제 빌드를 수행하면 정상적으로 동작합니다.

 

 

 

 

 

반응형

 

쿠버네티스의 구성에 대해 간략하게 알아봅니다.

 

 

 

1. 용어 정리

 

Container: 앱이 구동되는 환경까지 감싸 실행할 수 있도록 하는 격리 기술.
Container Runtime: 컨테이너를 다루는 도구
Docker: 컨테이너 런타임 중 가장 유명한 것.
Orchestration: 여러 서버에 걸친 컨테이너 및 사용 환경을 관리하는 행위.
Kubernetes: 컨테이너 런타임을 통해 컨테이너를 오케스트레이션 하는 도구.

 

 

 

2. Kubernetes의 역할

 

쿠버네티스의 역할은 컨테이너를 분산 배치, 상태 관리 및 컨테이너의 구동 환경까지 관리해 주는 도구이고, 도커는 컨테이너 런타임 중 하나입니다. 쿠버네티스는 컨테이너를 다루기 위해 도커 이외에도 다양한 컨테이너 런타임을 사용할 수 있습니다.

 

 

 

3. Kubernetes의 구성

 

쿠버네티스는 다음 그림과 같이 구성되어 있으며 크게 컨트롤 플레인 컴포넌트와 노드 컴포넌트로 나뉩니다.

 

https://kubernetes.io/ko/docs/concepts/overview/components/

 

3.1. 컨트롤 플레인(Control Plane) 컴포넌트

 

⇒ kube-apiserver

쿠버네티스 컨트롤 플레인의 프론트 엔드. 예를 들어 쿠버네티스 커맨드 라인 도구인 kubectl을 사용해 각종 명령을 수행할 경우 이 명령은 kube-apiserver로 전송됩니다. 이렇게 전달된 요청에 대하여 kube-apiserver는 이 요청의 처리 흐름에 따라 적절한 컴포넌트로 요청을 전달하는 역할까지 맡고 있습니다.

 

⇒ etcd

쿠버네티스 클러스터가 동작하기 위해서는 클러스터 및 리소스의 구성 정보, 상태 정보 및 명세 정보 등이 필요합니다. etcd는 이를 키-값(key-value) 형태로 저장하는 저장소입니다. 안정적인 동작을 위해 자료를 분산해서 저장하는 구조를 채택하고 있습니다.


⇒ kube-scheduler

쿠버네티스 클러스터는 여러 노드로 구성되어 있으며 기본적인 작업 단위라고 할 수 있는 파드는 여러 노드 중 특정 노드에 배치되어 동작하게 됩니다. 이때 새로 생성된 파드를 감지하여 어떤 노드로 배치할지 결정하는 작업을 스케줄링이라고 해요. 이런 스케줄링을 담당하는 컴포넌트가 kube-scheduler입니다.


⇒ kube-controller-manager

다운된 노드가 없는지, 파드가 의도한 복제(Replicas) 숫자를 유지하고 있는지, 서비스와 파드는 적절하게 연결되어 있는지, 네임스페이스에 대한 기본 계정과 토큰이 생성되어 있는지를 확인하고 적절하지 않다면 적절한 수준을 유지하기 위해 조치하는 역할을 하고 있습니다.

 

3.2. 노드(Node) 컴포넌트

 

⇒ kubelet

쿠블릿(kubelet)은 노드에서 컨테이너가 동작하도록 관리해주는 핵심 요소입니다. 각 노드에서 파드를 생성하고 정상적으로 동작하는지 관리하는 역할을 담당합니다 실제로 우리가 쿠버네티스의 워크로드를 관리하기 위해서 내리는 명령은 쿠블릿을 통해 수행된다고 볼 수 있습니다. 우리가 파드를 관리하기 위해 작성하는 yaml은 kube-apiserver를 통해 쿠블릿에 전달됩니다. 쿠블릿은 전달받은 yaml을 통해 파드를 생성하거나 변경하고 컨테이너가 정상적으로 실행되고 있는지 확인합니다.


⇒ container runtime

컨테이너 런타임은 파드에 포함 된 컨테이너 실행을 실질적으로 담당하는 애플리케이션을 의미합니다. 컨테이너 런타임은 쿠버네티스 구성요소에 기본적으로 포함되어있거나 특정 소프트웨어를 지칭하지 않습니다. 쿠버네티스가 컨테이너를 제어하기 위해 제공하는 표준 규약인 Container Runtime Imterface(CRI)를 준수하며 쿠버네티스와 함께 사용할 수 있는 외부 애플리케이션을 지칭합니다. 이런 CRI를 준수하는 대표적인 컨테이너 런타임은 containerd 혹은 CRI-O 등이 있습니다.


⇒ kube-proxy

kube-proxy는 쿠버네티스 클러스트 내부에서 네트워크 요청을 전달하는 역할을 합니다. 만약 kube-proxy가 없다면 쿠버네티스 내부에 위치한 특정 파드로 요청을 보내기 위해선 파드의 IP를 정확히 알아야 하며 이 IP를 외부에서 접근할 수 있도록 설정해야 합니다. 하지만 파드의 IP는 배포마다 변경되기 때문에 파드의 IP를 이용하는 방법은 쉽지 않습니다. 따라서 이러한 문제를 해결하기 위해 쿠버네티스는 오브젝트를 통해 고정적으로 파드에 접근할 수 있도록 하는 방법을 제공하고 요청이 실제 파드에 접근할 수 있도록 관리합니다. 이 관리를 담당하는 컴포넌트가 kube-proxy입니다.

 

 

 

4. 파드(Pod)

 

https://kubernetes.io/ko/docs/tutorials/kubernetes-basics/explore/explore-intro/

 

파드(Pod)는 쿠버네트스에서 생성하고 관리할 수 있는 배포 가능한 가장 작은 컴퓨팅 단위입니다. 하나 이상의 컨테이너 그룹을 의미하며 그룹 내 컨테이너는 스토리지 및 네트워크를 공유하게 됩니다. 

 

 

 

5. 워크로드

https://i.redd.it/mmauw9cprt161.png

 

워크로드는 쿠버네티스에서 구동되는 애플리케이션입니다. 워크로드가 단일 컴포넌트든 여러 컴포넌트든 관계없이 쿠버네티스에서는 워크로드를 일련의 파드 집합 내에서 실행합니다. 파드는 클러스터에서 실행 중인 컨테이너 집합을 의미합니다. 파드에는 정의된 라이프사이클이 있으나 사용자가 각 파드를 직접 관리할 필요는 없습니다. 대신 워크로드 리소스를 사용해 파드의 집합을 관리하게 됩니다.

 

 

 

References

 

 

 

 

반응형

 

 

자바 빌드 시스템에 대해 알아봅니다.

 

 

 

1. Maven

 

 

전통적인 빌드 툴입니다. 시작은 Apache ANT의 대안으로 시작되었으며 자바 프로젝트의 전체적인 관리를 가능하게 함과 동시에 많은 편리함과 이점을 제공해 줘 널리 사용되었습니다.

 

Project Object Model을 관리하는 pom.xml 파일을 사용하며 개발자가 해당 파일에 사용할 라이브러리를 정의해 두면 정의된 라이브러리뿐 아니라 그 라이브러리를 사용하는데 필요한 종속된 다른 라이브러리까지 관리해 자동으로 다운로드하여 사용할 수 있게 해 줍니다.

 

빌드 동작 방식이 미리 정해져 있으며 라이프사이클에 의해 순서에 맞게 동작합니다. Maven의 라이프사이클까지 자세히 다루진 않습니다.

 

 

 

2. Gradle

 

 

Gradle 역시 빌드 툴입니다. Maven 보다 늦게 출발한 후발주자입니다. Gradle은 기존 ANT와 Groovy기반으로 구축되어 기존의 ANT 역할과 배포 기능 모두 지원합니다.

 

Gradle은 늦게 만들어진 만큼 Maven에 비해 더 나은 사용성과 성능을 제공하고 있습니다. 안드로이드 앱의 공식 빌드 시스템이기도 하며 Java, C/C++, Python 등 다양한 언어에 대한 빌드를 지원하고 있습니다.

 

Maven과 달리 build.gradle 파일을 사용하며 Maven과 동일하게 개발자가 사용할 라이브러리를 정의해 둘 수 있습니다. Gradle 역시 정의된 라이브러리뿐 아니라 그 라이브러리를 사용하는데 필요한 종속된 다른 라이브러리까지 관리해 자동으로 다운로드하여 사용할 수 있게 해 줍니다.

 

 

 

3. Maven vs Gradle

 

사실 두 빌드 시스템은 자주 비교되곤 합니다. 성능과 편의성면에서는 당연히 Gradle의 우세입니다. 나중에 나왔으니 기존 Maven 보다 더 좋게 차별점을 두는 게 당연합니다.

 

당장 라이브러리를 관리하는 것만 봐도 그렇습니다. Maven의 경우 xml로 관리하고 Gradle의 경우 Groovy를 사용해 라이브러리가 많아질수록 관리적 측면과 가독성만 해도 엄청나게 차이 날게 뻔합니다. 심지어 Groovy를 사용해 개발자가 직접 스크립트를 작성해 빌드를 커스텀할 수도 있고 플러그인을 호출할 수도 있습니다.

 

 

성능면에서도 많이 차이가 납니다. 클린 상태에서 빌드도 거의 두배 가량 차이나고 심지어 캐싱된 상태에서는 최대 100배까지 차이가 납니다.

 

다른 다양한 이점도 있지만 여기까지만 들어도 모두가 다 Gradle을 사용하겠구나 생각할 수도 있습니다만 사실 Maven을 더 많이 사용한다고 합니다.

 

 

많은 사람들이 익숙함과 Groovy를 배워야 한다는 생각에 Maven을 사용하고 있을 수도 있습니다. 물론 개발자 포럼에 공유되어 있는 코드가 Maven으로 작성되어 있어서 빠르게 적용하기 위해서 그럴 수도 있습니다. 아니면 회사에서 사용하고 있던 제품 프로젝트의 빌드 시스템이 Maven으로 설정되어 있어서 그럴 수도 있고요.

 

하지만 아무리 생각해봐도 이제 더 이상 Maven을 고집할 이유는 모르겠습니다. 이미 사내에서 관리되고 있는 프로젝트가 아니라면 포럼이나 학습서에 Maven으로 작성되어 있어도 Gradle로 직접 바꿔서 시도해보는 것이 좋다고 생각합니다.

 

 

 

4. IntelliJ

 

 

IntelliJ를 IDE로 사용하고 새로운 Java 프로젝트를 생성할 때 보면 Build System에 Maven과 Gradle보다 IntelliJ라는 항목이 먼저 보였던 것을 기억하나요?

 

 

사실 앞서 다룬 내용처럼 대부분의 사용자는 Maven을 사용할 테고 다시 그 나머지 사용자의 대부분은 Gradle을 사용할 거로 생각합니다. StackOverflow와 같은 사이트를 보면 종종 IntelliJ에 관한 질문이 있긴 합니다. 결론은 "IntelliJ에서 제공해주는 독자적인 빌드 방식"입니다.

 

IntelliJ 빌드 시스템은 IntelliJ의 자체 빌드 메커니즘으로 단순하게 프로젝트의 모든 수정 내용과 종속 파일을 컴파일하는 기능입니다. 여기서 문제는 수정 내용과 종속된 파일만 빌드한다는데 있습니다. 안타깝게도 Maven과 Gradle과 달리 순수하게 빌드를 수행합니다. 그로 인해 아티팩트 생성, 리포지토리 배포, CodeGen과 같은 다른 작업을 수행하지 않습니다.  

 

위와 같은 이유로 인해 대부분의 개발자들은 Maven과 Gradle과 같은 빌드 툴을 사용합니다. 심지어 이 두 툴은 잘 사용한다면 개발자가 직접 지정한 빌드 구성을 설정할 수도 있습니다.

 

 

 

5. References

 

 

 

 

 

 

반응형

 

DICOM UID가 무엇인지와 구성 그리고 UID 생성 규칙에 대해 알아봅니다.

 

 

 

1. UID란

 

UID는 Unique Identifiers (UIDs)를 의미합니다. 말 그대로 다양한 항목에 대하여 고유하게 식별할 수 있는 기능을 제공하는 항목입니다. 다양한 사이트, 장비, 공급업체뿐 아니라 국가 범위에서 까지 고유성을 보장합니다. 

 

예를 들자면 당연히 동일한 UID를 갖고 StudyInstatnceUid, SeriesInstanceUid, SopInstanceUid를 사용해서는 안됩니다. 별개의 UID를 사용해 고유하게 식별할 수 있도록 해야 합니다. 또한 이미 할당된 UID에 접미사를 추가해 파생된 UID를 만들지 않도록 주의해야 합니다.

 

UID는 [ISO/IEC 8824] 표준에 정의된 숫자 형식의 OSI 개체 식별을 기반으로 합니다. DICOM 표준 콘텍스트 내에서 사용되는 모든 UID는 글로벌 고유성을 보장하기 위해 [ISO/IEC 9834-1]에 정의된 등록된 값을 사용합니다. 

 

 

 

2. UID의 구성

 

각각의 UID는 <org.root>와 <suffix>의 두 영역으로 구성되어 있습니다.

UID = <org root>.<suffix>

UID의 <org root> 부분은 제조업체, 연구 조직, NEMA 등 발행 기관을 고유하게 식별하며 [ISO/IEC 8824]에 정의된 여러 숫자 구성 요소로 구성됩니다.

UID의 <suffix> 부분도 여러 숫자 구성 요소로 구성되며 <org root> 범위 내에서 고유해야 합니다. 따라서 각 기관은 고유의 <org.root>를 갖게 되며 기관별로 <suffix>를 고유하게 발행해야 하므로 UID의 고유성이 유지됩니다.

 

예를 들어 <org root>에서 "1.2.840.10008"은 DICOM 전송 구문과 같은 DICOM 정의 항목용으로 이미 정의되어 있으며 이미지 인스턴스와 같은 개인적인 항목에는 사용할 수 없습니다.

 

UID를 구성할 때 UID가 어떠한 의미를 전달한다고 가정해서는 안 됩니다. 이는 UID는 특정 값이나 구성 요소를 찾기 위해 파싱 되지 않음을 의미합니다.

 

 

 

3. UID 인코딩 규칙.

 

UID 작성 시 몇 가지 규칙을 따라야 합니다.

  • UID의 각 구성 요소는 숫자이며 하나 이상의 숫자로 구성됩니다. 각 구성요소의 첫 번째 숫자는 구성요소가 단일 숫자가 아닌 한 0이 아니어야 합니다.
    • 기관은 중요하지 않은 0을 앞에 채워 배포할 수 있지만 인코딩 될 때 앞의 0은 무시되어야 합니다. 즉, "00029"는 "29"로 인코딩 되어야 합니다.
  • 각 구성 요소 숫자 값은 DICOM 기본 문자 레퍼토리인 [ISO 646]의 국제 참조 버전의 기본 G0 세트의 문자 0-9를 사용하여 인코딩 되어야 합니다.
  • 각 구성 요소는 "."(2EH) 문자로 구분해야 합니다.
  • Network negotiation에 사용되는 경우를 제외하고 홀수 바이트로 끝나는 경우에는 패딩 문자로 NULL(00H)이 하나 추가되어야 합니다.
  • UID는 숫자, 구분 기호, NULL(00H) 패딩 문자를 포함하여 총 64자를 초과할 수 없습니다.

 

 

 

 

 

반응형

+ Recent posts