๐Ÿš€ AutoMapper ์‚ฌ์šฉ๋ฒ•: ๊ฐ์ฒด ๊ฐ„ ๋งคํ•‘ ์ž๋™ํ™”์˜ ์‹ ์„ธ๊ณ„ ๐ŸŒŸ

์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿš€ AutoMapper ์‚ฌ์šฉ๋ฒ•: ๊ฐ์ฒด ๊ฐ„ ๋งคํ•‘ ์ž๋™ํ™”์˜ ์‹ ์„ธ๊ณ„ ๐ŸŒŸ

 

 

์•ˆ๋…•ํ•˜์„ธ์š”, ์—ฌ๋Ÿฌ๋ถ„! ์˜ค๋Š˜์€ C# ๊ฐœ๋ฐœ์ž๋“ค์˜ ์‚ถ์„ 180๋„ ๋ฐ”๊ฟ”๋†“์„ ๋งˆ๋ฒ• ๊ฐ™์€ ๋„๊ตฌ, AutoMapper์— ๋Œ€ํ•ด ์•Œ์•„๋ณผ ๊ฑฐ์˜ˆ์š”. ์ด ๊ธ€์„ ๋‹ค ์ฝ๊ณ  ๋‚˜๋ฉด ์—ฌ๋Ÿฌ๋ถ„๋„ AutoMapper ๋งˆ์Šคํ„ฐ๊ฐ€ ๋  ์ˆ˜ ์žˆ์„ ๊ฑฐ์˜ˆ์š”! ๐Ÿ˜Ž

AutoMapper๋Š” ๊ฐ์ฒด ๊ฐ„ ๋งคํ•‘์„ ์ž๋™ํ™”ํ•ด์ฃผ๋Š” ์ดˆ๊ฐ•๋ ฅ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ธ๋ฐ์š”, ์ด๊ฑธ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ”๋“œ ์ž‘์„ฑ ์‹œ๊ฐ„๋„ ์ค„์ด๊ณ , ์‹ค์ˆ˜๋„ ์ค„์ด๊ณ , ๊ฐœ๋ฐœ์ž์˜ ์‚ถ์˜ ์งˆ๋„ ์˜ฌ๋ผ๊ฐ„๋‹ต๋‹ˆ๋‹ค. ใ…‹ใ…‹ใ…‹

๊ทธ๋Ÿผ ์ง€๊ธˆ๋ถ€ํ„ฐ AutoMapper์˜ ์„ธ๊ณ„๋กœ ํ•จ๊ป˜ ๋น ์ ธ๋ณผ๊นŒ์š”? ๐ŸŠโ€โ™‚๏ธ

๐Ÿ”” ์ž ๊น! ์•Œ๋ ค๋“œ๋ฆด๊ฒŒ์š”

์ด ๊ธ€์€ ์žฌ๋Šฅ๋„ท(https://www.jaenung.net)์˜ '์ง€์‹์ธ์˜ ์ˆฒ' ๋ฉ”๋‰ด์—์„œ ๋งŒ๋‚˜๋ณด์‹ค ์ˆ˜ ์žˆ์–ด์š”. ์žฌ๋Šฅ๋„ท์—์„œ๋Š” ์ด๋Ÿฐ ์œ ์šฉํ•œ ์ •๋ณด๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋‹ค์–‘ํ•œ ์žฌ๋Šฅ๋„ ๊ฑฐ๋ž˜ํ•  ์ˆ˜ ์žˆ๋‹ต๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ ๊ด€๋ จ ๋„์›€์ด ํ•„์š”ํ•˜๋‹ค๋ฉด ์žฌ๋Šฅ๋„ท์„ ํ•œ ๋ฒˆ ๋‘˜๋Ÿฌ๋ณด๋Š” ๊ฒƒ๋„ ์ข‹์€ ๋ฐฉ๋ฒ•์ด์—์š”!

๐Ÿ“š AutoMapper, ๋„๋Œ€์ฒด ๋ญ๊ธธ๋ž˜?

์ž, ์—ฌ๋Ÿฌ๋ถ„! AutoMapper๊ฐ€ ๋ญ”์ง€ ๊ถ๊ธˆํ•˜์‹œ์ฃ ? ๊ฐ„๋‹จํžˆ ๋งํ•ด์„œ AutoMapper๋Š” ๊ฐ์ฒด์™€ ๊ฐ์ฒด ์‚ฌ์ด์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ž๋™์œผ๋กœ ๋งคํ•‘ํ•ด์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ˆ์š”. ๋ญ” ์†Œ๋ฆฌ๋ƒ๊ณ ์š”? ์‰ฝ๊ฒŒ ์„ค๋ช…ํ•ด๋“œ๋ฆด๊ฒŒ์š”! ๐Ÿ˜‰

์˜ˆ๋ฅผ ๋“ค์–ด, ์šฐ๋ฆฌ๊ฐ€ ์ด๋Ÿฐ ํด๋ž˜์Šค๋“ค์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ณ  ํ•ด๋ณผ๊นŒ์š”?


public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public DateTime BirthDate { get; set; }
}

public class UserDto
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public int Age { get; set; }
}

User ํด๋ž˜์Šค์˜ ๊ฐ์ฒด๋ฅผ UserDto ํด๋ž˜์Šค์˜ ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ์š”? ๋ณดํ†ต์€ ์ด๋ ‡๊ฒŒ ํ•˜์ฃ :


var user = new User { Id = 1, Name = "ํ™๊ธธ๋™", Email = "hong@example.com", BirthDate = new DateTime(1990, 1, 1) };
var userDto = new UserDto
{
    Id = user.Id,
    Name = user.Name,
    Email = user.Email,
    Age = DateTime.Now.Year - user.BirthDate.Year
};

์Œ... ์ข€ ๊ท€์ฐฎ์ฃ ? ๐Ÿ˜“ ํŠนํžˆ ํ”„๋กœํผํ‹ฐ๊ฐ€ ๋งŽ์•„์ง€๋ฉด ๋” ๊ท€์ฐฎ์•„์ ธ์š”. ์—ฌ๊ธฐ์„œ AutoMapper์˜ ๋“ฑ์žฅ! ์งœ์ž”~ ๐ŸŽ‰

AutoMapper๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด๋ ‡๊ฒŒ ๊ฐ„๋‹จํ•ด์ง‘๋‹ˆ๋‹ค:


var config = new MapperConfiguration(cfg => 
    cfg.CreateMap<user userdto>()
       .ForMember(dest => dest.Age, opt => opt.MapFrom(src => DateTime.Now.Year - src.BirthDate.Year)));
var mapper = config.CreateMapper();

var user = new User { Id = 1, Name = "ํ™๊ธธ๋™", Email = "hong@example.com", BirthDate = new DateTime(1990, 1, 1) };
var userDto = mapper.Map<userdto>(user);
</userdto></user>

์™€์šฐ! ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด User ๊ฐ์ฒด์˜ ๋ชจ๋“  ํ”„๋กœํผํ‹ฐ๊ฐ€ ์ž๋™์œผ๋กœ UserDto๋กœ ๋งคํ•‘๋˜๊ณ , Age๊นŒ์ง€ ๊ณ„์‚ฐ๋˜์–ด ๋“ค์–ด๊ฐ€์š”. ์™„์ „ ์‹ ์„ธ๊ณ„ ์•„๋‹Œ๊ฐ€์š”? ใ…‹ใ…‹ใ…‹

์ด๊ฒŒ ๋ฐ”๋กœ AutoMapper์˜ ๋งˆ๋ฒ•์ด์—์š”. ๊ฐ์ฒด ๊ฐ„ ๋งคํ•‘์„ ์ž๋™ํ™”ํ•ด์„œ ์šฐ๋ฆฌ์˜ ์ฝ”๋“œ๋ฅผ ๋” ๊น”๋”ํ•˜๊ณ , ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ ์‰ฝ๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๊ฑฐ์ฃ . ๐Ÿ‘

๐Ÿ’ก ๊ฟ€ํŒ

AutoMapper๋Š” ๋‹จ์ˆœํžˆ ๊ฐ์ฒด ๊ฐ„ ๋งคํ•‘๋งŒ ํ•ด์ฃผ๋Š” ๊ฒŒ ์•„๋‹ˆ์—์š”. ๋ณต์žกํ•œ ๋งคํ•‘ ๊ทœ์น™๋„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๊ณ , ์ปฌ๋ ‰์…˜ ๋งคํ•‘, ์ƒ์† ๊ด€๊ณ„์— ์žˆ๋Š” ๊ฐ์ฒด ๋งคํ•‘ ๋“ฑ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ๋“ค์€ ๋‚˜์ค‘์— ์ž์„ธํžˆ ์•Œ์•„๋ณผ ๊ฑฐ์˜ˆ์š”!

์ž, ์ด์ œ AutoMapper๊ฐ€ ๋ญ”์ง€ ๋Œ€์ถฉ ๊ฐ์ด ์˜ค์‹œ๋‚˜์š”? ๊ทธ๋Ÿผ ์ด์ œ๋ถ€ํ„ฐ ๋ณธ๊ฒฉ์ ์œผ๋กœ AutoMapper์˜ ์„ธ๊ณ„๋กœ ๋“ค์–ด๊ฐ€๋ณผ๊นŒ์š”? ์ค€๋น„๋˜์…จ๋‚˜์š”? Let's go! ๐Ÿš€

๐Ÿ› ๏ธ AutoMapper ์„ค์น˜ํ•˜๊ธฐ: ์ฒซ ๊ฑธ์Œ๋ถ€ํ„ฐ ์ฐจ๊ทผ์ฐจ๊ทผ

์ž, ์ด์ œ AutoMapper๋ฅผ ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•ด๋ณผ ์ฐจ๋ก€์˜ˆ์š”. ๊ทผ๋ฐ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋จผ์ € ์„ค์น˜๋ฅผ ํ•ด์•ผ๊ฒ ์ฃ ? ๊ฑฑ์ • ๋งˆ์„ธ์š”, ์•„์ฃผ ์‰ฌ์›Œ์š”! ๐Ÿ˜‰

1. NuGet ํŒจํ‚ค์ง€ ๋งค๋‹ˆ์ € ์‚ฌ์šฉํ•˜๊ธฐ

Visual Studio๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ๊ณ„์‹ ๋‹ค๋ฉด, NuGet ํŒจํ‚ค์ง€ ๋งค๋‹ˆ์ €๋ฅผ ํ†ตํ•ด ์‰ฝ๊ฒŒ AutoMapper๋ฅผ ์„ค์น˜ํ•  ์ˆ˜ ์žˆ์–ด์š”. ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์•„์š”:

  • ์†”๋ฃจ์…˜ ํƒ์ƒ‰๊ธฐ์—์„œ ํ”„๋กœ์ ํŠธ๋ฅผ ์šฐํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
  • 'NuGet ํŒจํ‚ค์ง€ ๊ด€๋ฆฌ'๋ฅผ ์„ ํƒํ•ด์š”.
  • ๊ฒ€์ƒ‰์ฐฝ์— 'AutoMapper'๋ฅผ ์ž…๋ ฅํ•˜๊ณ  ๊ฒ€์ƒ‰ํ•ด์š”.
  • AutoMapper ํŒจํ‚ค์ง€๋ฅผ ์ฐพ์•„ '์„ค์น˜' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•ด์š”.

์™€! ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด AutoMapper๊ฐ€ ์—ฌ๋Ÿฌ๋ถ„์˜ ํ”„๋กœ์ ํŠธ์— ์„ค์น˜๋ฉ๋‹ˆ๋‹ค. ์™„์ „ ์‰ฝ์ฃ ? ใ…‹ใ…‹ใ…‹

2. ํŒจํ‚ค์ง€ ๋งค๋‹ˆ์ € ์ฝ˜์†” ์‚ฌ์šฉํ•˜๊ธฐ

์ฝ˜์†” ๋ช…๋ น์–ด๋ฅผ ์ข‹์•„ํ•˜์‹ ๋‹ค๋ฉด, ํŒจํ‚ค์ง€ ๋งค๋‹ˆ์ € ์ฝ˜์†”์„ ํ†ตํ•ด ์„ค์น˜ํ•  ์ˆ˜๋„ ์žˆ์–ด์š”. ๋ฐฉ๋ฒ•์€ ์ด๋ ‡์Šต๋‹ˆ๋‹ค:

  • Visual Studio์—์„œ '๋„๊ตฌ' > 'NuGet ํŒจํ‚ค์ง€ ๊ด€๋ฆฌ์ž' > 'ํŒจํ‚ค์ง€ ๊ด€๋ฆฌ์ž ์ฝ˜์†”'์„ ์„ ํƒํ•ด์š”.
  • ์ฝ˜์†” ์ฐฝ์— ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•˜๊ณ  Enter๋ฅผ ๋ˆŒ๋Ÿฌ์š”:
Install-Package AutoMapper

์งœ์ž”~ ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด AutoMapper๊ฐ€ ์„ค์น˜๋ฉ๋‹ˆ๋‹ค! ๐Ÿ˜Ž

3. .NET CLI ์‚ฌ์šฉํ•˜๊ธฐ

.NET Core ํ”„๋กœ์ ํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ๊ณ„์‹œ๋‹ค๋ฉด, .NET CLI๋ฅผ ํ†ตํ•ด ์„ค์น˜ํ•  ์ˆ˜๋„ ์žˆ์–ด์š”. ํ„ฐ๋ฏธ๋„์ด๋‚˜ ๋ช…๋ น ํ”„๋กฌํ”„ํŠธ๋ฅผ ์—ด๊ณ  ํ”„๋กœ์ ํŠธ ๋””๋ ‰ํ† ๋ฆฌ๋กœ ์ด๋™ํ•œ ํ›„, ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜์„ธ์š”:

dotnet add package AutoMapper

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด AutoMapper๊ฐ€ ์—ฌ๋Ÿฌ๋ถ„์˜ ํ”„๋กœ์ ํŠธ์— ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค. ์™„์ „ ๊ฐ„๋‹จํ•˜์ฃ ?

๐Ÿ”” ์ฃผ์˜์‚ฌํ•ญ

AutoMapper๋ฅผ ์„ค์น˜ํ•  ๋•Œ๋Š” ํ•ญ์ƒ ์ตœ์‹  ๋ฒ„์ „์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์•„์š”. ํ•˜์ง€๋งŒ ํ”„๋กœ์ ํŠธ์˜ .NET ๋ฒ„์ „๊ณผ ํ˜ธํ™˜๋˜๋Š”์ง€ ๊ผญ ํ™•์ธํ•ด์•ผ ํ•ด์š”. ํ˜ธํ™˜์„ฑ ๋ฌธ์ œ๋กœ ๊ณจ์น˜ ์•„ํŒŒ์งˆ ์ˆ˜ ์žˆ๊ฑฐ๋“ ์š”! ๐Ÿ˜…

์ž, ์ด์ œ AutoMapper๋ฅผ ์„ค์น˜ํ–ˆ์–ด์š”. ์–ด๋•Œ์š”? ์ƒ๊ฐ๋ณด๋‹ค ์‰ฝ์ฃ ? ใ…‹ใ…‹ใ…‹

์ด์ œ ์šฐ๋ฆฌ๋Š” AutoMapper๋ฅผ ์‚ฌ์šฉํ•  ์ค€๋น„๊ฐ€ ์™„๋ฃŒ๋์–ด์š”. ๋‹ค์Œ ๋‹จ๊ณ„์—์„œ๋Š” AutoMapper๋ฅผ ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€ ์•Œ์•„๋ณผ ๊ฑฐ์˜ˆ์š”. ๊ธฐ๋Œ€๋˜์ง€ ์•Š๋‚˜์š”? ๐Ÿ˜ƒ

๊ทธ๋ฆฌ๊ณ  ์ž ๊น! ํ˜น์‹œ ๊ฐœ๋ฐœ ๊ด€๋ จํ•ด์„œ ๋„์›€์ด ๋” ํ•„์š”ํ•˜์‹ ๊ฐ€์š”? ๊ทธ๋ ‡๋‹ค๋ฉด ์žฌ๋Šฅ๋„ท(https://www.jaenung.net)์„ ํ•œ ๋ฒˆ ๋ฐฉ๋ฌธํ•ด๋ณด์„ธ์š”. ๋‹ค์–‘ํ•œ ๊ฐœ๋ฐœ ๊ด€๋ จ ์žฌ๋Šฅ์„ ๊ฐ€์ง„ ๋ถ„๋“ค๊ณผ ์—ฐ๊ฒฐ๋  ์ˆ˜ ์žˆ๋‹ต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์˜ ๊ฐœ๋ฐœ ์—ฌ์ •์— ํฐ ๋„์›€์ด ๋  ๊ฑฐ์˜ˆ์š”! ๐Ÿ‘จโ€๐Ÿ’ป๐Ÿ‘ฉโ€๐Ÿ’ป

์ž, ๊ทธ๋Ÿผ ๋‹ค์Œ ๋‹จ๊ณ„๋กœ ๋„˜์–ด๊ฐ€๋ณผ๊นŒ์š”? AutoMapper๋ฅผ ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณผ ์ฐจ๋ก€์˜ˆ์š”. ์ค€๋น„๋˜์…จ๋‚˜์š”? Let's go! ๐Ÿš€

๐ŸŽจ AutoMapper ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•: ์ฒซ ๋งคํ•‘ ๋งŒ๋“ค๊ธฐ

์ž, ์ด์ œ AutoMapper๋ฅผ ์„ค์น˜ํ–ˆ์œผ๋‹ˆ ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•ด๋ณผ ์ฐจ๋ก€์˜ˆ์š”. ์–ด๋–ป๊ฒŒ ํ•˜๋Š”์ง€ ๊ถ๊ธˆํ•˜์‹œ์ฃ ? ๊ฑฑ์ • ๋งˆ์„ธ์š”, ์ œ๊ฐ€ ์ฐจ๊ทผ์ฐจ๊ทผ ์„ค๋ช…ํ•ด๋“œ๋ฆด๊ฒŒ์š”! ๐Ÿ˜‰

1. ๋งคํ•‘ ์„ค์ •ํ•˜๊ธฐ

AutoMapper๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋จผ์ € ๋งคํ•‘ ์„ค์ •์„ ํ•ด์•ผ ํ•ด์š”. ์ด๊ฑด ์šฐ๋ฆฌ๊ฐ€ ์–ด๋–ค ๊ฐ์ฒด๋ฅผ ์–ด๋–ค ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ• ์ง€ AutoMapper์—๊ฒŒ ์•Œ๋ ค์ฃผ๋Š” ๊ณผ์ •์ด์—์š”. ์ฝ”๋“œ๋กœ ๋ณด๋ฉด ์ด๋ ‡๊ฒŒ ์ƒ๊ฒผ์–ด์š”:


var config = new MapperConfiguration(cfg => 
{
    cfg.CreateMap<source destination>();
});

IMapper mapper = config.CreateMapper();
</source>

์—ฌ๊ธฐ์„œ Source๋Š” ์›๋ณธ ๊ฐ์ฒด ํƒ€์ž…์ด๊ณ , Destination์€ ๋ณ€ํ™˜ํ•˜๊ณ ์ž ํ•˜๋Š” ๋Œ€์ƒ ๊ฐ์ฒด ํƒ€์ž…์ด์—์š”. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด AutoMapper๋Š” Source ํƒ€์ž…์˜ ๊ฐ์ฒด๋ฅผ Destination ํƒ€์ž…์˜ ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•  ์ค€๋น„๋ฅผ ๋งˆ์น˜๊ฒŒ ๋ผ์š”.

2. ๊ฐ์ฒด ๋งคํ•‘ํ•˜๊ธฐ

๋งคํ•‘ ์„ค์ •์„ ๋งˆ์ณค๋‹ค๋ฉด, ์ด์ œ ์‹ค์ œ๋กœ ๊ฐ์ฒด๋ฅผ ๋งคํ•‘ํ•  ์ˆ˜ ์žˆ์–ด์š”. ๋ฐฉ๋ฒ•์€ ์•„์ฃผ ๊ฐ„๋‹จํ•ด์š”:


var source = new Source { /* ์†์„ฑ ์„ค์ • */ };
var destination = mapper.Map<destination>(source);
</destination>

์งœ์ž”~ ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด source ๊ฐ์ฒด์˜ ๋ชจ๋“  ์†์„ฑ์ด destination ๊ฐ์ฒด๋กœ ์ž๋™์œผ๋กœ ๋ณต์‚ฌ๋ผ์š”. ์™„์ „ ์‹ ๊ธฐํ•˜์ง€ ์•Š๋‚˜์š”? ใ…‹ใ…‹ใ…‹

3. ์‹ค์ œ ์˜ˆ์ œ๋กœ ๋ณด๊ธฐ

์ž, ์ด์ œ ์‹ค์ œ ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด ๋” ์ž์„ธํžˆ ์•Œ์•„๋ณผ๊นŒ์š”? ์•„๊นŒ ๋ดค๋˜ User์™€ UserDto ํด๋ž˜์Šค๋ฅผ ๋‹ค์‹œ ํ•œ ๋ฒˆ ์‚ฌ์šฉํ•ด๋ณผ๊ฒŒ์š”:


public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public DateTime BirthDate { get; set; }
}

public class UserDto
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public int Age { get; set; }
}

// ๋งคํ•‘ ์„ค์ •
var config = new MapperConfiguration(cfg => 
{
    cfg.CreateMap<user userdto>()
       .ForMember(dest => dest.Age, opt => opt.MapFrom(src => DateTime.Now.Year - src.BirthDate.Year));
});

var mapper = config.CreateMapper();

// ๊ฐ์ฒด ์ƒ์„ฑ
var user = new User 
{ 
    Id = 1, 
    Name = "ํ™๊ธธ๋™", 
    Email = "hong@example.com", 
    BirthDate = new DateTime(1990, 1, 1) 
};

// ๋งคํ•‘ ์‹คํ–‰
var userDto = mapper.Map<userdto>(user);

Console.WriteLine($"Id: {userDto.Id}");
Console.WriteLine($"Name: {userDto.Name}");
Console.WriteLine($"Email: {userDto.Email}");
Console.WriteLine($"Age: {userDto.Age}");
</userdto></user>

์ด ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์™€์š”:


Id: 1
Name: ํ™๊ธธ๋™
Email: hong@example.com
Age: 33

์™€์šฐ! User ๊ฐ์ฒด์˜ ๋ชจ๋“  ์†์„ฑ์ด UserDto๋กœ ์ž˜ ๋งคํ•‘๋˜์—ˆ๊ณ , ์‹ฌ์ง€์–ด Age๊นŒ์ง€ ์ž๋™์œผ๋กœ ๊ณ„์‚ฐ๋˜์–ด ๋“ค์–ด๊ฐ”์–ด์š”. ์ด๊ฒŒ ๋ฐ”๋กœ AutoMapper์˜ ๊ฐ•๋ ฅํ•œ ํž˜์ด์—์š”! ๐Ÿ˜Ž

๐Ÿ’ก ๊ฟ€ํŒ

AutoMapper๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ฐ™์€ ์ด๋ฆ„์˜ ์†์„ฑ๋ผ๋ฆฌ ์ž๋™์œผ๋กœ ๋งคํ•‘ํ•ด์ค˜์š”. ํ•˜์ง€๋งŒ ์œ„ ์˜ˆ์ œ์ฒ˜๋Ÿผ ForMember() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํŠน์ • ์†์„ฑ์— ๋Œ€ํ•ด ์ปค์Šคํ…€ ๋งคํ•‘ ๊ทœ์น™์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ด๋ฅผ ํ†ตํ•ด ๋ณต์žกํ•œ ๋ณ€ํ™˜ ๋กœ์ง๋„ ์‰ฝ๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ต๋‹ˆ๋‹ค!

์ž, ์–ด๋– ์„ธ์š”? AutoMapper์˜ ๊ธฐ๋ณธ์ ์ธ ์‚ฌ์šฉ๋ฒ•์„ ๋ฐฐ์›Œ๋ดค๋Š”๋ฐ, ์ƒ๊ฐ๋ณด๋‹ค ์‰ฝ์ฃ ? ใ…‹ใ…‹ใ…‹

์ด์ œ ์—ฌ๋Ÿฌ๋ถ„๋„ AutoMapper๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ฐ์ฒด ๊ฐ„ ๋งคํ•‘์„ ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ์„ ๊ฑฐ์˜ˆ์š”. ํ•˜์ง€๋งŒ ์ด๊ฑด ์‹œ์ž‘์— ๋ถˆ๊ณผํ•ด์š”. AutoMapper์—๋Š” ๋” ๋งŽ์€ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ๋“ค์ด ์žˆ๋‹ต๋‹ˆ๋‹ค. ๋‹ค์Œ ์„น์…˜์—์„œ๋Š” ์ด๋Ÿฐ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ๋“ค์— ๋Œ€ํ•ด ์•Œ์•„๋ณผ ๊ฑฐ์˜ˆ์š”. ๊ธฐ๋Œ€๋˜์ง€ ์•Š๋‚˜์š”? ๐Ÿ˜ƒ

๊ทธ๋ฆฌ๊ณ  ์ž ๊น! ํ˜น์‹œ ์ด๋Ÿฐ ๊ฐœ๋ฐœ ์ง€์‹์„ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค๊ณผ ๋‚˜๋ˆ„๊ณ  ์‹ถ์œผ์‹ ๊ฐ€์š”? ๊ทธ๋ ‡๋‹ค๋ฉด ์žฌ๋Šฅ๋„ท(https://www.jaenung.net)์„ ํ™œ์šฉํ•ด๋ณด๋Š” ๊ฑด ์–ด๋–จ๊นŒ์š”? ์—ฌ๋Ÿฌ๋ถ„์˜ ์ง€์‹์„ ๊ณต์œ ํ•˜๊ณ , ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์˜ ์žฌ๋Šฅ๋„ ๋ฐฐ์šธ ์ˆ˜ ์žˆ๋Š” ์ข‹์€ ๊ธฐํšŒ๊ฐ€ ๋  ๊ฑฐ์˜ˆ์š”! ๐Ÿ‘จโ€๐Ÿซ๐Ÿ‘ฉโ€๐Ÿซ

์ž, ๊ทธ๋Ÿผ ๋‹ค์Œ ๋‹จ๊ณ„๋กœ ๋„˜์–ด๊ฐ€๋ณผ๊นŒ์š”? AutoMapper์˜ ๋” ๊นŠ์€ ์„ธ๊ณ„๋กœ ๋“ค์–ด๊ฐ€๋ณผ ์‹œ๊ฐ„์ด์—์š”. ์ค€๋น„๋˜์…จ๋‚˜์š”? Let's dive deeper! ๐ŸŠโ€โ™‚๏ธ

๐Ÿš€ AutoMapper ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ: ๋” ๊นŠ์ด ๋“ค์–ด๊ฐ€๋ณด์ž!

์ž, ์ด์ œ AutoMapper์˜ ๊ธฐ๋ณธ์„ ๋งˆ์Šคํ„ฐํ•˜์…จ์œผ๋‹ˆ ๋” ๊นŠ์ด ๋“ค์–ด๊ฐ€๋ณผ ์ฐจ๋ก€์˜ˆ์š”. AutoMapper์—๋Š” ์ •๋ง ๋‹ค์–‘ํ•œ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ๋“ค์ด ์žˆ๋‹ต๋‹ˆ๋‹ค. ์ด ๊ธฐ๋Šฅ๋“ค์„ ์•Œ๋ฉด ์—ฌ๋Ÿฌ๋ถ„์˜ ์ฝ”๋”ฉ ์‹ค๋ ฅ์ด ํ•œ ๋‹จ๊ณ„ ์—…๊ทธ๋ ˆ์ด๋“œ๋  ๊ฑฐ์˜ˆ์š”! ๐Ÿ˜Ž

1. ๋ณต์žกํ•œ ๋งคํ•‘ ๊ทœ์น™ ์„ค์ •ํ•˜๊ธฐ

๋•Œ๋กœ๋Š” ๋‹จ์ˆœํžˆ ์†์„ฑ ์ด๋ฆ„์ด ๊ฐ™๋‹ค๊ณ  ํ•ด์„œ ๋งคํ•‘์ด ๋˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋Š” ๋ถ€์กฑํ•  ๋•Œ๊ฐ€ ์žˆ์–ด์š”. ์ด๋Ÿด ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ๋ฐ”๋กœ ๋ณต์žกํ•œ ๋งคํ•‘ ๊ทœ์น™์ด์—์š”.


cfg.CreateMap<source destination>()
   .ForMember(dest => dest.FullName, opt => opt.MapFrom(src => src.FirstName + " " + src.LastName))
   .ForMember(dest => dest.Age, opt => opt.MapFrom(src => DateTime.Now.Year - src.BirthDate.Year));
</source>

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด Source์˜ FirstName๊ณผ LastName์„ ํ•ฉ์ณ์„œ Destination์˜ FullName์œผ๋กœ ๋งคํ•‘ํ•˜๊ณ , BirthDate๋ฅผ ์ด์šฉํ•ด Age๋ฅผ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ์–ด์š”. ์™„์ „ ๋˜‘๋˜‘ํ•˜์ฃ ? ใ…‹ใ…‹ใ…‹

2. ์กฐ๊ฑด๋ถ€ ๋งคํ•‘

ํŠน์ • ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋งคํ•‘์„ ๋‹ค๋ฅด๊ฒŒ ํ•˜๊ณ  ์‹ถ์„ ๋•Œ๊ฐ€ ์žˆ์ฃ ? ์ด๋Ÿด ๋•Œ๋Š” ์กฐ๊ฑด๋ถ€ ๋งคํ•‘์„ ์‚ฌ์šฉํ•ด์š”.


cfg.CreateMap<source destination>()
   .ForMember(dest => dest.Status, opt => opt.MapFrom(src => src.Age < 18 ? "Minor" : "Adult"))
   .ForMember(dest => dest.CanVote, opt => opt.Condition(src => src.Country == "USA"));
</source>

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋‚˜์ด์— ๋”ฐ๋ผ Status๋ฅผ ๋‹ค๋ฅด๊ฒŒ ์„ค์ •ํ•˜๊ณ , ๊ตญ๊ฐ€๊ฐ€ USA์ผ ๋•Œ๋งŒ CanVote ์†์„ฑ์„ ๋งคํ•‘ํ•  ์ˆ˜ ์žˆ์–ด์š”. ์™„์ „ ์œ ์—ฐํ•˜์ฃ ? ๐Ÿ˜‰

3. ์–‘๋ฐฉํ–ฅ ๋งคํ•‘

๋ณดํ†ต์€ A์—์„œ B๋กœ ๋งคํ•‘ํ•˜์ง€๋งŒ, ๋•Œ๋กœ๋Š” B์—์„œ A๋กœ๋„ ๋งคํ•‘ํ•ด์•ผ ํ•  ๋•Œ๊ฐ€ ์žˆ์–ด์š”. ์ด๋Ÿด ๋•Œ๋Š” ์–‘๋ฐฉํ–ฅ ๋งคํ•‘์„ ์‚ฌ์šฉํ•ด์š”.


cfg.CreateMap<source destination>()
   .ReverseMap();
</source>

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด Source์—์„œ Destination์œผ๋กœ, Destination์—์„œ Source๋กœ์˜ ๋งคํ•‘์ด ๋ชจ๋‘ ๊ฐ€๋Šฅํ•ด์ ธ์š”. ์–‘๋ฐฉํ–ฅ ์†Œํ†ต์ด ๊ฐ€๋Šฅํ•ด์ง€๋Š” ๊ฑฐ์ฃ ! ๐Ÿ‘ฅ

4. ์ƒ์† ๊ด€๊ณ„ ๋งคํ•‘

๊ฐ์ฒด ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ๋Š” ์ƒ์†์ด ์ค‘์š”ํ•˜์ฃ ? AutoMapper๋„ ์ƒ์† ๊ด€๊ณ„๋ฅผ ์ž˜ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด์š”.


cfg.CreateMap<animal animaldto>()
   .Include<dog dogdto>()
   .Include<cat catdto>();

cfg.CreateMap<dog dogdto>();
cfg.CreateMap<cat catdto>();
</cat></dog></cat></dog></animal>

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด Animal์„ AnimalDto๋กœ ๋งคํ•‘ํ•  ๋•Œ, Dog์™€ Cat ๊ฐ์ฒด๋„ ์•Œ๋งž๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ƒ์† ๊ด€๊ณ„๋„ ๋ฌธ์ œ์—†์ด ๋งคํ•‘! ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ

5. ์ปฌ๋ ‰์…˜ ๋งคํ•‘

๊ฐ์ฒด ํ•˜๋‚˜๋งŒ ๋งคํ•‘ํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ๋ฆฌ์ŠคํŠธ๋‚˜ ๋ฐฐ์—ด ๊ฐ™์€ ์ปฌ๋ ‰์…˜์„ ๋งคํ•‘ํ•ด์•ผ ํ•  ๋•Œ๋„ ์žˆ์ฃ ? AutoMapper๋Š” ์ด๊ฒƒ๋„ ์‰ฝ๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด์š”.


var sourceList = new List<source> { /* ์†Œ์Šค ๊ฐ์ฒด๋“ค */ };
var destinationList = mapper.Map<list>>(sourceList);
</list></source>

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์†Œ์Šค ๋ฆฌ์ŠคํŠธ์˜ ๊ฐ ์š”์†Œ๊ฐ€ ๋Œ€์ƒ ํƒ€์ž…์œผ๋กœ ๋ณ€ํ™˜๋˜์–ด ์ƒˆ๋กœ์šด ๋ฆฌ์ŠคํŠธ๊ฐ€ ๋งŒ๋“ค์–ด์ ธ์š”. ๋ฆฌ์ŠคํŠธ๋„ ํ•œ ๋ฒˆ์— ๋ณ€์‹ ! ๐Ÿ”„

6. ๋™์  ๋งคํ•‘

๋•Œ๋กœ๋Š” ๋งคํ•‘ ์„ค์ •์„ ๋ฏธ๋ฆฌ ํ•˜์ง€ ์•Š๊ณ , ๋Ÿฐํƒ€์ž„์— ๋™์ ์œผ๋กœ ๋งคํ•‘์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•  ๋•Œ๊ฐ€ ์žˆ์–ด์š”. AutoMapper๋Š” ์ด๋Ÿฐ ์ƒํ™ฉ๋„ ์ง€์›ํ•ด์š”.


var source = new ExpandoObject();
source.FirstName = "John";
source.LastName = "Doe";

var destination = mapper.Map<destination>(source);
</destination>

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋™์  ๊ฐ์ฒด๋„ ๋งคํ•‘ํ•  ์ˆ˜ ์žˆ์–ด์š”. ๋Ÿฐํƒ€์ž„์— ๊ฐ์ฒด์˜ ๊ตฌ์กฐ๊ฐ€ ๊ฒฐ์ •๋˜๋”๋ผ๋„ ๋ฌธ์ œ์—†์ฃ ! ๋™์ ์ด๊ณ  ์œ ์—ฐํ•ด! ๐Ÿคธโ€โ™‚๏ธ

๐Ÿ’ก ๊ฟ€ํŒ

AutoMapper์˜ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ๋“ค์„ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ํ•ญ์ƒ ์„ฑ๋Šฅ์„ ๊ณ ๋ คํ•ด์•ผ ํ•ด์š”. ๋ณต์žกํ•œ ๋งคํ•‘ ๊ทœ์น™์ด๋‚˜ ๋™์  ๋งคํ•‘์€ ํŽธ๋ฆฌํ•˜์ง€๋งŒ, ๋•Œ๋กœ๋Š” ์„ฑ๋Šฅ ์ €ํ•˜๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ์–ด์š”. ๊ผญ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•˜๊ณ , ๊ฐ€๋Šฅํ•˜๋ฉด ๊ฐ„๋‹จํ•œ ๋งคํ•‘์„ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ต๋‹ˆ๋‹ค!

์–ด๋•Œ์š”? AutoMapper์˜ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ๋“ค์„ ์‚ดํŽด๋ดค๋Š”๋ฐ, ์ •๋ง ๋‹ค์–‘ํ•˜๊ณ  ๊ฐ•๋ ฅํ•˜์ฃ ? ใ…‹ใ…‹ใ…‹

์ด๋Ÿฐ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ๋“ค์„ ์ž˜ ํ™œ์šฉํ•˜๋ฉด, ์—ฌ๋Ÿฌ๋ถ„์˜ ์ฝ”๋“œ๋Š” ๋”์šฑ ๊ฐ•๋ ฅํ•˜๊ณ  ์œ ์—ฐํ•ด์งˆ ๊ฑฐ์˜ˆ์š”. ํ•˜์ง€๋งŒ ๋„ˆ๋ฌด ๋ณต์žกํ•˜๊ฒŒ ๋งŒ๋“ค์ง€ ์•Š๋„๋ก ์ฃผ์˜ํ•ด์•ผ ํ•ด์š”. ๋‹จ์ˆœํ•จ์ด ๋•Œ๋กœ๋Š” ์ตœ๊ณ ์˜ ๋ฏธ๋•์ด๋ž๋‹ˆ๋‹ค! ๐Ÿ˜‰

๊ทธ๋ฆฌ๊ณ  ์ž ๊น! ์ด๋Ÿฐ ๊ณ ๊ธ‰ ๊ธฐ์ˆ ์„ ์ตํžˆ๋‹ค ๋ณด๋ฉด ๋•Œ๋กœ๋Š” ๋ง‰ํžˆ๋Š” ๋ถ€๋ถ„์ด ์žˆ์„ ์ˆ˜ ์žˆ์–ด์š”. ๊ทธ๋Ÿด ๋•Œ๋Š” ์žฌ๋Šฅ๋„ท(https://www.jaenung.net)์„ ํ™œ์šฉํ•ด๋ณด๋Š” ๊ฑด ์–ด๋–จ๊นŒ์š”? ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๋“ค์˜ ๋„์›€์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๊ณ , ์—ฌ๋Ÿฌ๋ถ„์˜ ์ง€์‹๋„ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ๋Š” ์ข‹์€ ๊ธฐํšŒ๊ฐ€ ๋  ๊ฑฐ์˜ˆ์š”! ๐Ÿ’ก

์ž, ์ด์ œ AutoMapper์˜ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ๋“ค๋„ ์‚ดํŽด๋ดค์–ด์š”. ๋‹ค์Œ ์„น์…˜์—์„œ๋Š” AutoMapper๋ฅผ ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•˜๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ์ฃผ์˜ํ•ด์•ผ ํ•  ์ ์€ ๋ฌด์—‡์ธ์ง€ ์•Œ์•„๋ณผ ๊ฑฐ์˜ˆ์š”. ์ค€๋น„๋˜์…จ๋‚˜์š”? Let's go to the next level! ๐Ÿš€

๐Ÿ—๏ธ ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ AutoMapper ํ™œ์šฉํ•˜๊ธฐ

์ž, ์ด์ œ AutoMapper์˜ ๊ธฐ๋ณธ๋ถ€ํ„ฐ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ๊นŒ์ง€ ๋‹ค ๋ฐฐ์› ์–ด์š”. ๊ทผ๋ฐ ์ด๊ฑธ ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•ด์•ผ ํ• ๊นŒ์š”? ๊ฑฑ์ • ๋งˆ์„ธ์š”, ์ œ๊ฐ€ ๋‹ค ์•Œ๋ ค๋“œ๋ฆด๊ฒŒ์š”! ๐Ÿ˜‰

1. ์˜์กด์„ฑ ์ฃผ์ž…(Dependency Injection) ํ™œ์šฉํ•˜๊ธฐ

์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” AutoMapper๋ฅผ ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ†ตํ•ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์•„์š”. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ฝ”๋“œ์˜ ๊ฒฐํ•ฉ๋„๋ฅผ ๋‚ฎ์ถ”๊ณ  ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์‰ฌ์›Œ์ง„๋‹ต๋‹ˆ๋‹ค.


// Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    services.AddAutoMapper(typeof(Startup));
}

// ์‚ฌ์šฉํ•    ํด๋ž˜์Šค์—์„œ
public class UserService
{
    private readonly IMapper _mapper;

    public UserService(IMapper mapper)
    {
        _mapper = mapper;
    }

    public UserDto GetUser(int id)
    {
        var user = // ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋กœ์ง
        return _mapper.Map<userdto>(user);
    }
}
</userdto>

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด AutoMapper๋ฅผ ์„œ๋น„์Šค๋กœ ๋“ฑ๋กํ•˜๊ณ , ํ•„์š”ํ•œ ๊ณณ์—์„œ ์ฃผ์ž…๋ฐ›์•„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์š”. ๊น”๋”ํ•˜๊ณ  ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ ์ข‹์€ ์ฝ”๋“œ๊ฐ€ ๋˜๋Š” ๊ฑฐ์ฃ ! ๐Ÿ‘

2. ํ”„๋กœํ•„(Profile) ์‚ฌ์šฉํ•˜๊ธฐ

๋งคํ•‘ ์„ค์ •์ด ๋งŽ์•„์ง€๋ฉด ๊ด€๋ฆฌํ•˜๊ธฐ ์–ด๋ ค์›Œ์งˆ ์ˆ˜ ์žˆ์–ด์š”. ์ด๋Ÿด ๋•Œ๋Š” AutoMapper์˜ Profile ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹์•„์š”.


public class UserProfile : Profile
{
    public UserProfile()
    {
        CreateMap<user userdto>()
            .ForMember(dest => dest.FullName, opt => opt.MapFrom(src => $"{src.FirstName} {src.LastName}"))
            .ForMember(dest => dest.Age, opt => opt.MapFrom(src => DateTime.Now.Year - src.BirthDate.Year));
        
        CreateMap<userdto user>();
    }
}

// Startup.cs
services.AddAutoMapper(typeof(Startup));
</userdto></user>

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋งคํ•‘ ์„ค์ •์„ ๊น”๋”ํ•˜๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด์š”. ํ”„๋กœํ•„๋ณ„๋กœ ๋งคํ•‘์„ ๊ตฌ๋ถ„ํ•˜๋‹ˆ๊นŒ ์ฝ”๋“œ๋„ ๋” ์ฝ๊ธฐ ์‰ฌ์›Œ์ง€์ฃ ! ๐Ÿ˜Ž

3. ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์ถ”๊ฐ€ํ•˜๊ธฐ

๋งคํ•‘ ๊ณผ์ •์—์„œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๋” ์•ˆ์ „ํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์–ด์š”.


CreateMap<source destination>()
    .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name))
    .ForMember(dest => dest.Age, opt => {
        opt.PreCondition(src => src.Age > 0);
        opt.MapFrom(src => src.Age);
    });
</source>

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด Age๊ฐ€ 0๋ณด๋‹ค ํฐ ๊ฒฝ์šฐ์—๋งŒ ๋งคํ•‘์ด ์ด๋ฃจ์–ด์ ธ์š”. ์ž˜๋ชป๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋“ค์–ด๊ฐ€๋Š” ๊ฑธ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์ฃ ! ์•ˆ์ „์ œ์ผ! ๐Ÿ›ก๏ธ

4. ์„ฑ๋Šฅ ์ตœ์ ํ™”ํ•˜๊ธฐ

AutoMapper๋Š” ํŽธ๋ฆฌํ•˜์ง€๋งŒ, ์ž˜๋ชป ์‚ฌ์šฉํ•˜๋ฉด ์„ฑ๋Šฅ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ์–ด์š”. ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ๋‹ต๋‹ˆ๋‹ค.

  • ๋งคํ•‘ ์„ค์ •์„ ์•ฑ ์‹œ์ž‘ ์‹œ ํ•œ ๋ฒˆ๋งŒ ํ•˜์„ธ์š”.
  • ๋ณต์žกํ•œ ๋งคํ•‘์€ ํ”ผํ•˜๊ณ , ๊ผญ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•˜์„ธ์š”.
  • ๋Œ€๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋งคํ•‘ํ•  ๋•Œ๋Š” ProjectTo๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

var users = dbContext.Users.ProjectTo<userdto>(_mapper.ConfigurationProvider).ToList();
</userdto>

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฟผ๋ฆฌ ๋‹จ๊ณ„์—์„œ ๋งคํ•‘์ด ์ด๋ฃจ์–ด์ ธ์„œ ์„ฑ๋Šฅ์ด ํฌ๊ฒŒ ํ–ฅ์ƒ๋ผ์š”! ๋น ๋ฅธ ๊ฒƒ์ด ์ข‹์€ ๊ฑฐ์•ผ~ ๐Ÿš€

5. ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์ž‘์„ฑํ•˜๊ธฐ

AutoMapper๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋„ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ด์š”. ๋งคํ•‘์ด ์ œ๋Œ€๋กœ ์ด๋ฃจ์–ด์ง€๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๊ฑฐ๋“ ์š”.


[Fact]
public void AutoMapper_Configuration_IsValid()
{
    var config = new MapperConfiguration(cfg => cfg.AddProfile<userprofile>());
    config.AssertConfigurationIsValid();
}

[Fact]
public void Map_User_To_UserDto_IsCorrect()
{
    // Arrange
    var user = new User { Id = 1, FirstName = "John", LastName = "Doe", BirthDate = new DateTime(1990, 1, 1) };
    var mapper = new Mapper(new MapperConfiguration(cfg => cfg.AddProfile<userprofile>()));

    // Act
    var userDto = mapper.Map<userdto>(user);

    // Assert
    Assert.Equal(1, userDto.Id);
    Assert.Equal("John Doe", userDto.FullName);
    Assert.Equal(DateTime.Now.Year - 1990, userDto.Age);
}
</userdto></userprofile></userprofile>

์ด๋ ‡๊ฒŒ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ๋งคํ•‘ ์„ค์ •์— ๋ฌธ์ œ๊ฐ€ ์—†๋Š”์ง€, ์‹ค์ œ๋กœ ๋งคํ•‘์ด ์ œ๋Œ€๋กœ ์ด๋ฃจ์–ด์ง€๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด์š”. ํ…Œ์ŠคํŠธ๋Š” ์‚ฌ๋ž‘์ž…๋‹ˆ๋‹ค~ โค๏ธ

๐Ÿ’ก ๊ฟ€ํŒ

AutoMapper๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ํ•ญ์ƒ 'Convention over Configuration' ์›์น™์„ ๊ธฐ์–ตํ•˜์„ธ์š”. ๊ฐ€๋Šฅํ•œ ํ•œ ๊ธฐ๋ณธ ๊ทœ์น™์„ ๋”ฐ๋ฅด๊ณ , ๊ผญ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์ปค์Šคํ…€ ๋งคํ•‘์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์•„์š”. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ฝ”๋“œ๊ฐ€ ๋” ๊ฐ„๊ฒฐํ•ด์ง€๊ณ  ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ ์‰ฌ์›Œ์ง„๋‹ต๋‹ˆ๋‹ค!

์ž, ์ด์ œ AutoMapper๋ฅผ ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•˜๋Š”์ง€ ์•Œ์•„๋ดค์–ด์š”. ์–ด๋•Œ์š”? ์ƒ๊ฐ๋ณด๋‹ค ์‰ฝ์ฃ ? ใ…‹ใ…‹ใ…‹

์ด๋ ‡๊ฒŒ AutoMapper๋ฅผ ์ž˜ ํ™œ์šฉํ•˜๋ฉด ์ฝ”๋“œ์˜ ํ’ˆ์งˆ๋„ ๋†’์•„์ง€๊ณ , ๊ฐœ๋ฐœ ์‹œ๊ฐ„๋„ ๋‹จ์ถ•ํ•  ์ˆ˜ ์žˆ์–ด์š”. ํ•˜์ง€๋งŒ ํ•ญ์ƒ ์ฃผ์˜ํ•ด์•ผ ํ•  ์ ์€ ์žˆ์–ด์š”. ๋„ˆ๋ฌด ๋ณต์žกํ•œ ๋งคํ•‘์€ ์˜คํžˆ๋ ค ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์œผ๋‹ˆ, ์ ์ ˆํžˆ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ด์š”!

๊ทธ๋ฆฌ๊ณ  ์ž ๊น! ํ˜น์‹œ ์ด๋Ÿฐ ์‹ค์ œ ํ”„๋กœ์ ํŠธ ๊ฒฝํ—˜์„ ๋” ์Œ“๊ณ  ์‹ถ์œผ์‹ ๊ฐ€์š”? ๊ทธ๋ ‡๋‹ค๋ฉด ์žฌ๋Šฅ๋„ท(https://www.jaenung.net)์„ ํ™œ์šฉํ•ด๋ณด๋Š” ๊ฑด ์–ด๋–จ๊นŒ์š”? ์‹ค์ œ ํ”„๋กœ์ ํŠธ์— ์ฐธ์—ฌํ•˜๊ฑฐ๋‚˜, ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๋“ค๊ณผ ๊ฒฝํ—˜์„ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋Š” ์ข‹์€ ๊ธฐํšŒ๊ฐ€ ๋  ๊ฑฐ์˜ˆ์š”! ๐ŸŒŸ

์ž, ์ด์ œ ์šฐ๋ฆฌ์˜ AutoMapper ์—ฌํ–‰์ด ๊ฑฐ์˜ ๋๋‚˜๊ฐ€๊ณ  ์žˆ์–ด์š”. ๋งˆ์ง€๋ง‰์œผ๋กœ AutoMapper ์‚ฌ์šฉ ์‹œ ์ฃผ์˜ํ•ด์•ผ ํ•  ์ ๋“ค๊ณผ ๋ช‡ ๊ฐ€์ง€ ํŒ์„ ์ •๋ฆฌํ•ด๋ณผ๊นŒ์š”? ์ค€๋น„๋˜์…จ๋‚˜์š”? Let's wrap it up! ๐ŸŽ

๐ŸŽฏ AutoMapper ์‚ฌ์šฉ ์‹œ ์ฃผ์˜์‚ฌํ•ญ ๋ฐ ํŒ

์ž, ์ด์ œ AutoMapper์˜ ๊ฑฐ์˜ ๋ชจ๋“  ๊ฒƒ์„ ๋ฐฐ์› ์–ด์š”. ํ•˜์ง€๋งŒ ์ž ๊น! AutoMapper๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ฃผ์˜ํ•ด์•ผ ํ•  ์ ๋“ค์ด ์žˆ์–ด์š”. ์ด ์ ๋“ค๋งŒ ์ž˜ ๊ธฐ์–ตํ•˜๋ฉด ์—ฌ๋Ÿฌ๋ถ„์€ ์ง„์ •ํ•œ AutoMapper ๋งˆ์Šคํ„ฐ๊ฐ€ ๋  ์ˆ˜ ์žˆ์„ ๊ฑฐ์˜ˆ์š”! ๐Ÿ˜Ž

1. ์„ฑ๋Šฅ์— ์ฃผ์˜ํ•˜์„ธ์š”

AutoMapper๋Š” ํŽธ๋ฆฌํ•˜์ง€๋งŒ, ์ž˜๋ชป ์‚ฌ์šฉํ•˜๋ฉด ์„ฑ๋Šฅ ์ €ํ•˜์˜ ์›์ธ์ด ๋  ์ˆ˜ ์žˆ์–ด์š”.

  • ๋งคํ•‘ ์„ค์ •์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์‹œ ํ•œ ๋ฒˆ๋งŒ ํ•˜์„ธ์š”.
  • ๋ณต์žกํ•œ ๋งคํ•‘์€ ํ”ผํ•˜๊ณ , ๊ผญ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•˜์„ธ์š”.
  • ๋Œ€๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋งคํ•‘ํ•  ๋•Œ๋Š” ProjectTo๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด AutoMapper๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด์„œ๋„ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ์–ด์š”. ๋น ๋ฅธ ๊ฒŒ ์ข‹์ž–์•„์š”? ๐Ÿš€

2. ๋งคํ•‘ ๊ทœ์น™์€ ๋ช…ํ™•ํ•˜๊ฒŒ

๋ณต์žกํ•œ ๋งคํ•‘ ๊ทœ์น™์€ ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด์š”. ๊ฐ€๋Šฅํ•œ ํ•œ ๊ฐ„๋‹จํ•˜๊ณ  ๋ช…ํ™•ํ•œ ๋งคํ•‘ ๊ทœ์น™์„ ์‚ฌ์šฉํ•˜์„ธ์š”.


// ์ข‹์€ ์˜ˆ
CreateMap<source destination>()
    .ForMember(dest => dest.FullName, opt => opt.MapFrom(src => $"{src.FirstName} {src.LastName}"));

// ๋‚˜์œ ์˜ˆ
CreateMap<source destination>()
    .ForMember(dest => dest.FullName, opt => opt.MapFrom(src => 
        src.Title + " " + src.FirstName + " " + src.MiddleName + " " + src.LastName + " " + src.Suffix));
</source></source>

๊ฐ„๋‹จํ•˜๊ณ  ๋ช…ํ™•ํ•œ ๋งคํ•‘ ๊ทœ์น™์„ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์›Œ์ ธ์š”. ๋‹จ์ˆœํ•จ์ด ์ตœ๊ณ ! ๐Ÿ‘

3. Null ๊ฐ’ ์ฒ˜๋ฆฌ์— ์ฃผ์˜ํ•˜์„ธ์š”

๋งคํ•‘ ๊ณผ์ •์—์„œ Null ๊ฐ’์„ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ• ์ง€ ๋ช…ํ™•ํžˆ ์ •์˜ํ•ด์•ผ ํ•ด์š”. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์˜ˆ์ƒ์น˜ ๋ชปํ•œ NullReferenceException์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์–ด์š”.


CreateMap<source destination>()
    .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name ?? "Unknown"));
</source>

์ด๋ ‡๊ฒŒ Null ๊ฐ’์„ ๋ช…์‹œ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋ฉด ์•ˆ์ „ํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์–ด์š”. ์•ˆ์ „์ œ์ผ! ๐Ÿ›ก๏ธ

4. ์–‘๋ฐฉํ–ฅ ๋งคํ•‘์€ ์‹ ์ค‘ํ•˜๊ฒŒ

ReverseMap์„ ์‚ฌ์šฉํ•œ ์–‘๋ฐฉํ–ฅ ๋งคํ•‘์€ ํŽธ๋ฆฌํ•˜์ง€๋งŒ, ๋•Œ๋กœ๋Š” ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋‚ณ์„ ์ˆ˜ ์žˆ์–ด์š”. ๊ผญ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•˜์„ธ์š”.


CreateMap<source destination>()
    .ForMember(dest => dest.FullName, opt => opt.MapFrom(src => $"{src.FirstName} {src.LastName}"))
    .ReverseMap()
    .ForMember(src => src.FirstName, opt => opt.Ignore())
    .ForMember(src => src.LastName, opt => opt.Ignore());
</source>

์ด๋ ‡๊ฒŒ ReverseMap์„ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ๋งคํ•‘ ๊ทœ์น™์„ ๋ช…ํ™•ํžˆ ์ •์˜ํ•ด์•ผ ํ•ด์š”. ์–‘๋ฐฉํ–ฅ์ด๋ผ๊ณ  ๋‹ค ์ข‹์€ ๊ฑด ์•„๋‹ˆ์—์š”! โš–๏ธ

5. ๋ฒ„์ „ ๊ด€๋ฆฌ์— ์ฃผ์˜ํ•˜์„ธ์š”

AutoMapper์˜ ๋ฒ„์ „์ด ๋ณ€๊ฒฝ๋˜๋ฉด ๋งคํ•‘ ๋™์ž‘์ด ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์–ด์š”. ํ•ญ์ƒ ์ตœ์‹  ๋ฒ„์ „์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ํ™•์ธํ•˜๊ณ , ํ•„์š”ํ•˜๋‹ค๋ฉด ๋งคํ•‘ ์„ค์ •์„ ์—…๋ฐ์ดํŠธํ•˜์„ธ์š”.

๋ฒ„์ „ ๊ด€๋ฆฌ๋ฅผ ์ž˜ ํ•˜๋ฉด ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์˜ค๋ฅ˜๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ตœ์‹ ์ด ์ข‹๊ธด ํ•œ๋ฐ, ์‹ ์ค‘ํ•˜๊ฒŒ! ๐Ÿ•ต๏ธโ€โ™‚๏ธ

6. ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜์„ธ์š”

AutoMapper ์„ค์ •์ด ์˜ฌ๋ฐ”๋ฅธ์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜์„ธ์š”. ํŠนํžˆ ๋ณต์žกํ•œ ๋งคํ•‘ ๊ทœ์น™์ด ์žˆ๋Š” ๊ฒฝ์šฐ์—๋Š” ๋”์šฑ ์ค‘์š”ํ•ด์š”.


[Fact]
public void AutoMapper_Configuration_IsValid()
{
    var config = new MapperConfiguration(cfg => cfg.AddProfile<myprofile>());
    config.AssertConfigurationIsValid();
}
</myprofile>

๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ด ๋งคํ•‘ ์„ค์ •์˜ ์˜ค๋ฅ˜๋ฅผ ๋ฏธ๋ฆฌ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ์–ด์š”. ํ…Œ์ŠคํŠธ๋Š” ์‚ฌ๋ž‘์ž…๋‹ˆ๋‹ค~ โค๏ธ

๐Ÿ’ก ์ตœ์ข… ๊ฟ€ํŒ

AutoMapper๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ํ•ญ์ƒ 'KISS' ์›์น™์„ ๊ธฐ์–ตํ•˜์„ธ์š”. Keep It Simple, Stupid! ๊ฐ€๋Šฅํ•œ ํ•œ ๊ฐ„๋‹จํ•˜๊ฒŒ ์œ ์ง€ํ•˜๊ณ , ๋ณต์žกํ•œ ๋งคํ•‘์€ ํ”ผํ•˜์„ธ์š”. ๊ทธ๋ฆฌ๊ณ  ํ•ญ์ƒ ์„ฑ๋Šฅ๊ณผ ๊ฐ€๋…์„ฑ ์‚ฌ์ด์˜ ๊ท ํ˜•์„ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ด์š”. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด AutoMapper์˜ ์ง„์ •ํ•œ ํž˜์„ ๋Š๋‚„ ์ˆ˜ ์žˆ์„ ๊ฑฐ์˜ˆ์š”!

์ž, ์ด์ œ ์ •๋ง AutoMapper์˜ ๋ชจ๋“  ๊ฒƒ์„ ๋ฐฐ์› ์–ด์š”. ์–ด๋– ์„ธ์š”? ์ƒ๊ฐ๋ณด๋‹ค ๋งŽ์€ ๋‚ด์šฉ์ด์—ˆ์ฃ ? ใ…‹ใ…‹ใ…‹

ํ•˜์ง€๋งŒ ๊ฑฑ์ • ๋งˆ์„ธ์š”. ์ด ๋ชจ๋“  ๋‚ด์šฉ์„ ํ•œ ๋ฒˆ์— ์™„๋ฒฝํ•˜๊ฒŒ ์ดํ•ดํ•˜๊ณ  ์ ์šฉํ•˜๊ธฐ๋Š” ์–ด๋ ค์›Œ์š”. ์ค‘์š”ํ•œ ๊ฑด ์ด๋Ÿฐ ์ ๋“ค์„ ์•Œ๊ณ  ์žˆ๋‹ค๋Š” ๊ฑฐ์˜ˆ์š”. ์‹ค์ œ๋กœ ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•˜๋ฉด์„œ ํ•˜๋‚˜์”ฉ ์ตํ˜€๋‚˜๊ฐ€๋ฉด ๋ผ์š”.

๊ทธ๋ฆฌ๊ณ  ์žŠ์ง€ ๋งˆ์„ธ์š”! ๊ฐœ๋ฐœ์€ ํ˜ผ์ž ํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ์—์š”. ์–ด๋ ค์šด ์ ์ด ์žˆ๋‹ค๋ฉด ์–ธ์ œ๋“  ๋™๋ฃŒ๋“ค์—๊ฒŒ ๋ฌผ์–ด๋ณด๊ฑฐ๋‚˜, ์žฌ๋Šฅ๋„ท(https://www.jaenung.net) ๊ฐ™์€ ํ”Œ๋žซํผ์„ ํ†ตํ•ด ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๋“ค์˜ ๋„์›€์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์–ด์š”. ํ•จ๊ป˜ ์„ฑ์žฅํ•˜๋Š” ๊ฒŒ ๊ฐ€์žฅ ๋น ๋ฅธ ๊ธธ์ด๋ž๋‹ˆ๋‹ค! ๐ŸŒฑ

์ž, ์ด์ œ ์—ฌ๋Ÿฌ๋ถ„์€ AutoMapper์˜ ์ง„์ •ํ•œ ๋งˆ์Šคํ„ฐ๊ฐ€ ๋˜์—ˆ์–ด์š”. ์ด ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ๋ฅผ ํ™œ์šฉํ•ด์„œ ๋ฉ‹์ง„ ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์„ธ์š”. ์—ฌ๋Ÿฌ๋ถ„์˜ ์ฝ”๋“œ๊ฐ€ ๋”์šฑ ๊น”๋”ํ•˜๊ณ  ํšจ์œจ์ ์œผ๋กœ ๋ณ€ํ•  ๊ฑฐ์˜ˆ์š”. ํ™”์ดํŒ…! ๐Ÿ’ช