๋ธ๋ก๊ทธ ์ด์
http://blog.aliencube.org
๋ธ๋ก๊ทธ ์ฃผ์๋ ๋์ผํฉ๋๋ค๋ง, ํ ๋ธ๋ฌ์์ ์๋ํ๋ ์ค๋ก ์ด์ ํฉ๋๋ค. ์ด๊ณณ์ ํฌ์คํธ๋ ๋ชจ๋ ์ฎ๊ฒจ์ก์ต๋๋ค๋ง ๋ฐฑ์ ์ฐจ์์์ ๋จ๊ฒจ๋ก๋๋ค.
wallacepolsom

oozey mess
let's talk about Bridgerton tea, my ask is open
AnasAbdin
will byers stan first human second

pixel skylines

็ฅๆฅ / Permanent Vacation
Acquired Stardust
noise dept.

izzy's playlists!
Monterey Bay Aquarium
sheepfilms

JVL
we're not kids anymore.
$LAYYYTER
hello vonnie
cherry valley forever

ellievsbear

JBB: An Artblog!
seen from Romania

seen from Canada

seen from Singapore
seen from United States
seen from Philippines

seen from United States
seen from Germany
seen from Malaysia
seen from United States
seen from China
seen from United States

seen from United States

seen from United States

seen from Ecuador
seen from United States
seen from Canada

seen from New Zealand

seen from Tรผrkiye

seen from United States
seen from United States
@aliencube-community
๋ธ๋ก๊ทธ ์ด์
http://blog.aliencube.org
๋ธ๋ก๊ทธ ์ฃผ์๋ ๋์ผํฉ๋๋ค๋ง, ํ ๋ธ๋ฌ์์ ์๋ํ๋ ์ค๋ก ์ด์ ํฉ๋๋ค. ์ด๊ณณ์ ํฌ์คํธ๋ ๋ชจ๋ ์ฎ๊ฒจ์ก์ต๋๋ค๋ง ๋ฐฑ์ ์ฐจ์์์ ๋จ๊ฒจ๋ก๋๋ค.

Anya is live and ready to show you everything. Watch her strip, dance, and perform exclusive shows just for you. Interact in real-time and make your fantasies come true.
Free to watch โข No registration required โข HD streaming
๋ฐ๋ฉํ ๋ฅด์ ๋ฒ์น Law of Demeter
๋ฐ๋ฉํ ๋ฅด๋ ๊ทธ๋ฆฌ์ค ์ ํ์ ๋์ค๋ ์ถ์์ ์ ์ด๋ค. ๋ก๋ง์ ํ์์๋ ์ธ๋ ์ค Ceres ๋ผ๊ณ ๋ถ๋ฆฌ๋ ๋ฐ๋ก ๊ทธ ์ . ํ์ง๋ง, ๊ทธ ๋ฐ๋ฉํ ๋ฅดํ๊ณ ์ด ๋ฒ์นํ๊ณ ๋ ์๊ด์๋ค๋ ๊ฒ์ด ํจ์ . [์ํคํผ๋์]1์์๋ ๋ฐ๋ฉํ ๋ฅด์ ๋ฒ์น์ ์๋์ ๊ฐ์ด ์ ์ํ๊ณ ์๋ค.
๋ฐ๋ฉํ ๋ฅด์ ๋ฒ์น์์๋ ์ด๋ค ๊ฐ์ฒด O์ ๋ฉ์๋ m๋ ๋ค์๊ณผ ๊ฐ์ ์ข ๋ฅ์ ๊ฐ์ฒด์ ์๋ ๋ฉ์๋๋ค๋ง ์คํ์ํฌ ์ ์๋ค.
O ์์ฒด
m ์ ๋ณ์
m ์์์ ๋ง๋ค์ด์ง ๊ฐ์ฒด
O๊ฐ ์ง์ ๊ด๋ฆฌํ๋ ์ฝคํฌ๋ํธ ๊ฐ์ฒด
m์ ์ค์ฝํ ์์์ O๊ฐ ์ ๊ทผ ๊ฐ๋ฅํ ์ ์ญ๋ณ์
์ข ๋ง์ด ์ด๋ ค์ด๋ฐ, Richard Carr์ [The Law of Demeter]2 ํฌ์คํธ์ ์ข ๋ ์ฌ์ด ์ค๋ช ์ด ์๋ค.
์ด๋ค ํด๋ผ์ค์ ๋ฉค๋ฒ โ ๋ฉ์๋ ๋๋ ์์ฑ โ ๋ ๋ฐ๋์ ๋ค์๊ณผ ๊ฐ์ ๊ฐ์ฒด๋ค์ ๋ฉค๋ฒ๋ค๋ง์ ์คํ์์ผ์ผ ํ๋ค:
ํด๋น ๋ฉ์๋ ๋๋ ์์ฑ์ด ์ ์ธ๋ ๊ฐ์ฒด
๋ฉ์๋์ ํ๋ผ๋ฏธํฐ๋ก ๋ณด๋ด์ง ๊ฐ์ฒด
๋ฉ์๋ ๋๋ ์์ฑ์ด ์ง์ ์ด๊ธฐํ์ํจ ๊ฐ์ฒด
ํธ์ถ์ ์ํ ๋ฉ์๋ ๋๋ ์์ฑ์ผ๋ก์ ๊ฐ์ ํด๋ผ์ค ์์์ ์ ์ธ๋ ๊ฐ์ฒด
์ ์ญ ๊ฐ์ฒด
์๋ ์์ ์ฝ๋๋ฅผ ๋ณด์. ASP.NET MVC ์น์ฌ์ดํธ๋ฅผ ๊ฐ๋ฐํ๋ค๋ณด๋ฉด ์ฝํธ๋กค๋ฌ์์ ํํ ๋ณผ ์ ์๋ ์ํฉ์ด๋ค.
public class ProductController : Controller { private IProductService _service; public ProductController(IProductService service) { this._service = service; } public ActionResult Index() { var products = this._service.Repository.Get(); return View(products); } } public class ProductService : IProductService { public ProductService(IProductRepository repository) { this.Repository = repository; } public IProductRepository Repository { get; private set; } }
์์ ์ฝ๋์์ Index ์ก์ ์ ๋ณด๋ฉด ๋๋ต ์์์ด ๊ฐ๋ฅํ๊ฒ ์ง๋ง ProductService๋ผ๋ ์๋น์ค ๋ ์ด์ด ์์์ ProductRepository๋ผ๋ ๋ฐ์ดํฐ ๋ฆฌํฌ์งํ ๋ฆฌ ํจํด์ ํตํด CRUD๋ฅผ ๊ตฌํํ๊ณ ์๋ค. Index ์ก์ ์ ์ ์ฒด ์ ํ ๋ฆฌ์คํธ๋ฅผ ๋ณด์ฌ์ฃผ๋ ๋ทฐ๋ฅผ ๊ฐ๊ณ ์์ด์ ์ ์ฒด ์ ํ ๋ฆฌ์คํธ๋ ์๋น์ค ์์ ๊ตฌํ๋ ๋ฆฌํฌ์งํ ๋ฆฌ์ Get ๋ฉ์๋๋ฅผ ํตํด ๊ฐ์ ธ์ค๊ฒ ๋๋ค. ์ด๋ ๊ฒ ๋ฉ์๋ ์ฒด์ด๋์ ํ๋ ๊ฒ์ด ๋ฐ๋ก ๋ฐ๋ฉํ ๋ฅด์ ๋ฒ์น์ ์๋ฐํ๋ ๊ฒ์ด ๋๋ค. ProductController ๊ฐ์ฒด๋ ์์ฑ์๋ฅผ ํตํด ๋ณ์๋ก ๋ฐ์ ProductService ๊ฐ์ฒด์ ๋ฉ์๋ ๋๋ ์์ฑ์ ํธ์ถํด์ผ ํ์ง ๊ทธ ๋ด๋ถ์ ์๋ ProductRepository ๊ฐ์ฒด์ Get ๋ฉ์๋๋ฅผ ์ง์ ํธ์ถํด์๋ ์๋๋ค. ProductRepository ๊ฐ์ฒด์ ํ์ฌ ์ํ๊ฐ null์ด๋ผ๋ฉด ํด๋น ์ฝ๋๋ NullReferenceException์ ๋์ง๊ธฐ ๋๋ฌธ์ด๋ค. ๋ฐ๋ผ์ ProductService ํด๋ผ์ค ์์ ์ถ๊ฐ์ ์ธ ๋ฉ์๋๋ฅผ ์ ์ธํด์ฃผ๋ ๋ฐฉ์์ผ๋ก ๋ฆฌํฉํ ๋ง์ ํด์ผ ํ๋ค.
public class ProductController : Controller { private IProductService _service; public ProductController(IProductService service) { this._service = service; } public ActionResult Index() { var products = this._service.GetProducts(); return View(products); } } public class ProductService : IProductService { private IProductRepository _repository; public ProductService(IProductRepository repository) { this._repository = repository; } public IList<Product> GetProducts() { return this._repository.Get(); } }
์ฆ ProductRepository ๊ฐ์ฒด๋ฅผ public ์์ฑ์ด๋ ํ๋๋ก ๋๋ ๊ฒ์ด ์๋๋ผ ๋ด๋ถ์ ์ผ๋ก encapsulation ์ํค๊ณ ProductRepository ํด๋ผ์ค์ ๋ฉค๋ฒ๋ ProductService ํด๋ผ์ค์ ๋ฉค๋ฒ๋ฅผ ํตํด ํธ์ถํ๋ ๋ฐฉ์์ผ๋ก ํ๊ฒ ๋๋ฉด, ProductController ํด๋ผ์ค๋ ์ง์ ์ ์ผ๋ก ๊ด๋ จ์ด ์๋ ์ฝคํฌ๋ํธ์ธ ProductSerivce์ ๋ํด์๋ง ํต์ ๊ถ์ ๊ฐ์ง ์ ์์ด์ ๋ณด๋ค ์์ ํ๊ณ ์ ์ฐํ ์ฝ๋๋ฅผ ์์ฑํ ์ ์๊ฒ ๋๋ค.
์ด๋ฐ์์ผ๋ก ๋ฉ์๋ ์ฒด์ด๋์ ์ต๋ํ ์ค์ด๋ ๊ฒ์ด ๋ฐ๋์งํ ๊ฐ์ฒด์งํฅ ํ๋ก๊ทธ๋๋ฐ์ด๋ผ๊ณ ํ ์ ์๊ฒ ๋ค. ํ์ง๋ง ์ด๋ ๊ฒ ํ๋ก๊ทธ๋๋ฐ์ ํ๊ฒ ๋๋ฉด ์ถ๊ฐ์ ์ธ ๋ฉ์๋๋ฅผ ์์ฑํด์ผ ํ๋ ๋ถ๋ด์ด ์๊ธฐ๊ฒ ๋๋๋ฐ, ์ด๊ฒ์ด ๊ผญ ๋ถ์ ์ ์ด๋ผ๊ณ ๋ ํ ์ ์๋ ๊ฒ์ด ๊ฐ์ฒด ์ฌ์ด์ ์์กด์ฑ์ ์ต์ํํ๋ ๋ฐฉ์์ผ๋ก ์ ์ฐํ๊ฒ ๊ฐ๋ฐ์ ํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
๋จ, LINQ๋ฅผ ์ฐ๋ ์ํฉ์ด๋ผ๋ฉด ์๊ธฐ๊ฐ ๋ฌ๋ผ์ง๋ค. LINQ์์๋ ํน์ฑ์ ๋ฉ์๋ ์ฒด์ด๋์ด ํ์์ผ ์ ๋ฐ์ ์๋์ง๋ผ, ์ด ๋ฐ๋ฉํ ๋ฅด์ ๋ฒ์น์์ ๋ฒ์ด๋ ์ ์๋๋ฐ, ๊ทธ ์ด์ ๋ ๋ฉ์๋ ์ฒด์ด๋์ ํ๋ ๊ฒ๊ณผ ์๊ด์์ด ํญ์ ๋ฆฌํดํ์ ์ด ๋์ผํ๊ธฐ ๋๋ฌธ์ด๋ค. ์์ ์์ ์ฝ๋์ ๋์จ ProductRepository ํด๋ผ์ค์ Get ๋ฉ์๋๋ ์๋ง๋ ๋ด๋ถ์ ์ผ๋ก ์๋์ ๊ฐ์ด ๊ตฌํ์ด ๋์ด ์์ ๊ฒ์ด๋ค.
public class ProductRepository : IProductRepository { private CompanyDataContext _context; public ProductRepository(ICompanyDataContext context) { this._context = context as CompanyDataContext; } public IList<Product> Get() { return this._context .Products .Where(p => p.IsActive) .OrderBy(p => p.DateRegistered) .ToList(); } }
์ฌ๊ธฐ์ Products, Where ๊ทธ๋ฆฌ๊ณ OrderBy๋ ๋ชจ๋ ๋์ผํ IEnumerable<Product> ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค. ์ฆ LINQ๋ฅผ ์ด์ฉํ ๋ฉ์๋ ์ฒด์ด๋์ ๊ฒฝ์ฐ ๋ฉ์๋๋ง๋ค ๋์ผํ ๋ฐ์ดํฐ ํ์ ์ ๋ฐํํ๊ธฐ ๋๋ฌธ์ ์ด ๋ฐ๋ฉํ ๋ฅด์ ๋ฒ์น์ ์๋ฐํ์ง ์๊ณ ์์ ํ๊ฒ ์ฌ์ฉํ ์ ์๋ค.
์ฐธ์กฐ:
[Law of Demeter]1 from Wikipedia
[The Law of Demeter]2 by Richard Carr
http://en.wikipedia.org/wiki/Law_of_Demeterย โฉ๏ธ โฉ๏ธ
http://www.blackwasp.co.uk/LawOfDemeter.aspxย โฉ๏ธ โฉ๏ธ
์ํฐํฐ ํ๋ ์์ํฌ Code First ๋ฐฉ๋ฒ๋ก #3
์ํฐํฐ ํ๋ ์์ํฌ Code First ๋ฐฉ๋ฒ๋ก #1
์ํฐํฐ ํ๋ ์์ํฌ Code First ๋ฐฉ๋ฒ๋ก #2
์ํฐํฐ ํ๋ ์์ํฌ Code First ๋ฐฉ๋ฒ๋ก #3
Foreign Key ์ค์ ํ๊ธฐ
์์ Data Annotation ๋ฐฉ๋ฒ์ ํตํด ํ ์ด๋ธ์ ์ปฌ๋ผ๋ค์ ๋ํ ์์ฑ์ ์ ์ดํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์์๋ณด์๋ค. ์ด๋ฒ์๋ ํ ์ด๋ธ ๊ฐ๊ฐ์ ๋ํ ๊ด๊ณ๋ฅผ ์ค์ ํ๋ ๋ฐฉ๋ฒ์ ๋ํด ๋ ผ์ํด ๋ณด๋๋ก ํ์.
ํ์ฌ Products ํ ์ด๋ธ๊ณผ Orders ํ ์ด๋ธ์ ๊ฐ๊ฐ ์ํ ์ ๋ณด, ์ฃผ๋ฌธ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์๋ค. ์ด ๋์ many-to-many ๊ด๊ณ์ด๋ฏ๋ก, ์ ๊ทํ๋ฅผ ๊ฑฐ์ณ one-to-many ๊ด๊ณ๋ก ๋ฐ๊พธ์ด ์ฃผ์ด์ผ ํ๋๋ฐ, ๊ทธ ๊ฒฐ๊ณผ๋ก ProductOrders ํ ์ด๋ธ์ด ๋ง๋ค์ด์ก๋ค. ๋ฐ๋ผ์, ์ด ProductOrders ํ ์ด๋ธ์ ์๋ ProductId์ OrderId๊ฐ Forein Key ๋ก์ ์ญํ ์ ํด์ผ ํ๋ค. ์๋์ ๊ฐ์ด ProductOrder ํด๋ผ์ค๋ฅผ ์์ ํด ๋ณด์.
public class ProductOrder { [Key] public int ProductOrderId { get; set; } [Required(ErrorMessage = "ProductId must be set")] public int ProductId { get; set; } [ForeignKey("ProductId")] public virtual Product Product { get; set; } [Required(ErrorMessage = "OrderId must be set")] public int OrderId { get; set; } [ForeignKey("OrderId")] public virtual Order Order { get; set; } [Required(ErrorMessage = "AmountOrdered must be set")] public int AmountOrdered { get; set; } }
์ ์ฝ๋์์ ์ฃผ๋ชฉํด์ผ ํ ๋ถ๋ถ์ public virtual Product Product { get; set; } ๋ถ๋ถ๊ณผ public virtual Order Order { get; set; } ๋ถ๋ถ์ด๋ค. ProductOrder ํด๋ผ์ค๊ฐ ProductId, OrderId ํ๋๋ฅผ ๊ฐ๊ฐ ํด๋นํ๋ Product, Order ํด๋ผ์ค์ Foreign Key ๋ก์ ์ธ์์ํค๊ธฐ ์ํ์ฌ ๋ฒ์ถ์ผ ํ๋กํผํฐ๋ฅผ ์ถ๊ฐ์์ผฐ๋ค. ์ด๋ ๊ฒ ์ถ๊ฐ์์ผ ์ปดํ์ผ ํ ํ, F5 ํค๋ฅผ ๋ค์ ํ ๋ฒ ๋๋ฌ ์ด ๋ณ๊ฒฝ์ฌํญ์ ๋ฐ์์์ผ ๋ณด์. ๊ทธ๋ฆฌ๊ณ , SQL Server Management Studio ๋ฅผ ํตํด ๋ณ๊ฒฝ๋ ์ฌํญ์ ํ์ธํด ๋ณด๋๋ก ํ์.
์ ์ด๋ฏธ์ง์์ ๋ณผ ์ ์๋ค์ํผ ProductId์ OrderId๊ฐ Foreign Key๋ก ์ง์ ์ด ๋์๊ณ , ํด๋นํ๋ ํค๊ฐ์ ํ ์ด๋ธ ์คํค๋ง์ ํ ์ด๋ธ ์ด๋ฆ์ ์กฐํฉ โ ์ฌ๊ธฐ์๋ dbo.ProductOrders_dbo.Products_ProductId โ ์ผ๋ก ์ด๋ฃจ์ด์ง ๊ฒ์ ๋ณผ ์ ์๋ค.
๋ค์์๋ Fluent API๋ฅผ ์ด์ฉํ์ฌ ํ ์ด๋ธ์ ์์ฑํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด๋๋ก ํ์.
AngularJS ๋ํ๋์ ์ธ์ ์ (DI) ์ดํดํ๊ธฐ
๊ฐ์ฒด์งํฅ ํ๋ก๊ทธ๋๋ฐ์์ Dependency Injection (DI) ๊ฐ๋ ์ ์์ฃผ ์ค์ํ๋ฐ, ๊ฐ๋ณ ๊ฐ์ฒด๋ค ์ฌ์ด์ ์์กด์ฑ์ด ์ค์ด๋ค์ด์ผ โ ๋ค๋ฅธ ๋ง๋ก ๋์จํ ๊ฒฐํฉ (loosely coupled)์ ์ด๋ฃจ๊ฑฐ๋ โ ์ ์ง๋ณด์ ๋ฐ ํ์ฅ์ฑ, ๊ทธ๋ฆฌ๊ณ ํ ์คํธ ๊ฐ์ฉ์ฑ ์ธก๋ฉด์์ ๋ง์ ์ด๋์ ๋ณผ ์ ์๋ค. ์ผ๋ฐ์ ์ผ๋ก Java ๋๋ C# ํ๋ก๊ทธ๋๋ฐ์์๋ ์๋์ ๊ฐ์ ํํ๋ก DI๋ฅผ ๊ตฌ์ฑํ๋ค.
public class ProductController : ApiController { public ProductController(IProductService service) { this._service = service; } private IProductService _service; public HttpResponseMessage Get(int id) { var product = this._service.GetProduct(id); return new HttpResponseMessage(200, product); } }
์์ ์ฝ๋๋ C#์ผ๋ก ๊ตฌํํ ๊ฐ๋จํ Web API ์ฝํธ๋กค๋ฌ์ด๋ค. ์ฝํธ๋กค๋ฌ ์ธ์คํด์ค๋ฅผ ์ด๊ธฐํํ ๋, ์์ฑ์์ ํ๋ผ๋ฏธํฐ๋ก์ IProductService ์ธํฐํ์ด์ค๋ฅผ ๊ฐ์ง ์ธ์คํด์ค๋ฅผ ์ฃผ์ ์ํจ๋ค. ์ด๋ ๊ฒ ํ๋ฉด ์ ์ฝํธ๋กค๋ฌ๋ ํ๋ผ๋ฏธํฐ๋ก ๋ค์ด์จ ์ธ์คํด์ค๊ฐ ์ด๋ป๊ฒ ๋ด๋ถ์ ์ผ๋ก ๊ตฌํ์ด ๋๋์ง ์ ํ์๊ฐ ์๋ค. ๋ฐ๋ผ์, ProductService ํด๋ผ์ค์ ๋ณ๊ฒฝ์ฌํญ์ด ์๊ฒจ๋ ์๋ฌด๋ฐ ๋ฌธ์ ๊ฐ ๋์ง ์๋๋ค.
์ด๋ฐ ์์ผ๋ก DI๋ฅผ ๊ตฌ์ฑํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ธ๋ฐ, AngularJS์์๋ ๋ ํนํ ๋ฐฉ์์ผ๋ก DI๋ฅผ ์์ฑํ๋ค. ์๋ฌด๋๋ ์๋ฐ์คํฌ๋ฆฝํธ๋ผ๋ ์คํฌ๋ฆฝํธ ์ธ์ด์ ํน์ฑ ๋๋ฌธ์ด ์๋๊น ์ถ๊ธฐ๋ ํ๋ฐ, ์ด๋ถ๋ถ์ ์ฌ๊ธฐ์ ๋ ผ์ํ ๊ฒ์ ์๋๋ ๋ค๋ฅธ ๊ธฐํ๋ฅผ ์ด์ฉํ๋๋ก ํ์. AngularJS์์ DI๋ฅผ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ์๋นํ ๋ค์ํ๋ค. ์ฐ์ ๊ฐ๋จํ HTML ์ฝ๋๋ฅผ ์์ฑํด ๋ณด์.
<html ng-app="diSample"> <body> <div ng-controller="sampleController"> <ul> <li>text: {{text}}</li> <li>di1text1: {{di1text1}}</li> <li>di1text2: {{di1text2}}</li> <li>di2text: {{di2text}}</li> <li>di3text: {{di3text}}</li> <li>di4text: {{di4text}}</li> <li>di5text: {{di5text}}</li> <li>di6text: {{di6text}}</li> <li>di7text: {{di7text}}</li> </ul> </div> </body> </html>
diSample์ด๋ผ๋ ๋ชจ๋์ sampleController๋ฅผ ํตํด ์ด ์ํ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ธ๋ฉ ์ํค๋ ๋ชจ๋ธ์ด๋ค. ์ ์ฝํธ๋กค๋ฌ๋ฅผ ๋ด์ ์๋ฐ์คํฌ๋ฆฝํธ๋ ์๋์ ๊ฐ๋ค.
(function(angular) { var module = angular.module("diSample", []); module.controller("sampleController", function($scope) { $scope.text = "TEXT"; }); })(angular);
์ด๋ ๊ฒ ํ๋ฉด {{text}} ๋ถ๋ถ์ด TEXT๋ก ๋ฐ๋์ด ๋์ค๊ฒ ๋๋ค. ์ฌ๊ธฐ์ DI๋ฅผ ์ ์ฉ์์ผ๋ณด์. ์ฐ์ $provide ์๋น์ค๋ฅผ ์ด์ฉํ๋ ๋ฐฉ๋ฒ์ด๋ค.
module.config(function ($provide) { $provide.provider("di1", function(){ this.$get = function(){ return function($scope, text) { $scope.di1text2 = "DI1 TEXT 2"; return text; }; }; }); });
$provide ์๋น์ค๋ฅผ ์ด์ฉํด์ di1์ด๋ผ๋ ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ค. ๊ทธ๋ฆฌ๊ณ ์ฝํธ๋กค๋ฌ ์ ์ธ๋ถ๋ถ์ ์๋์ ๊ฐ์ด ์์ ํด ์ค๋ค.
module.controller("sampleController", function($scope, di1) { $scope.text = "TEXT"; $scope.di1text1 = di1($scope, "DI1 TEXT 1"); });
์ด๋ ๊ฒ ํ๋ฉด ์ฝํธ๋กค๋ฌ์์ di1() ์ธ์คํด์ค๋ฅผ ํธ์ถํ๊ฒ ๋๋ฉด ๊ทธ ๊ฒฐ๊ณผ๊ฐ $scope.di1text1๊ณผ $scope.di1text2์ ๋ฐ์๋์ด ํ๋ฉด์ ๋ํ๋๋ค. ํ์ง๋ง, ์ด๊ฒ๋ณด๋ค ์ข ๋ ๊ฐ๋จํ ๋ฐฉ๋ฒ์ผ๋ก ๋์ผํ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์๋ค. ์์ module.config() ์์ชฝ์ ์๋์ ๊ฐ์ ์ฝ๋๋ฅผ ๋ฃ๋๋ค.
$provide.factory("di2", function(){ return function(text) { return text; }; });
์ด๊ฒ์ ์์ $provide.provider() ํ์ ์ ์ข ๋ ๊ฐ๋จํ๊ฒ ํ ๊ฒ์ผ๋ก $provide.factory() ํ์ ์ ์ฐ๊ณ ์๋ค. ์ด๊ฒ์ ๋์ฑ ๊ฐ๋จํ๊ฒ ํ๋ฉด ์๋์ ๊ฐ์ด $provide.value() ํํ๋ก๋ ์ธ ์ ์๋ค.
$provide.value("di3", function(text) { return text; });
์ด์ ์ฝํธ๋กค๋ฌ๋ฅผ ์๋์ ๊ฐ์ด ๋ฐ๊พธ์ด๋ณด์.
module.controller("sampleController", function($scope, di1, d2, d3) { $scope.text = "TEXT"; $scope.di1text1 = di1($scope, "DI1 TEXT 1"); $scope.di2text = di2("DI2 TEXT"); $scope.di3text = di3("DI3 TEXT"); });
์ด๋ ๊ฒ ์ฝํธ๋กค๋ฌ๋ฅผ ๋ณ๊ฒฝํ ํ์ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํด ๋ณด๋ฉดdi1, di2, di3 ๊ฐ์ฒด๊ฐ ์ด๋ป๊ฒ ์ฐ์๋์ง ์ ์ ์๋ค. ์ฌ์ง์ด ์ด๋ณด๋ค ๋ ๊ฐ๋จํ๊ฒ DI๋ฅผ ์ ์ฉ์ํฌ ์๋ ์๋ค. ์์ ์์ ์ฝ๋๋ ๋ชจ๋ module.config() ์์ $provide ์๋น์ค๋ฅผ ํฌํจ์ํจ ํ ๊ทธ ์ค์ฝํ ์์์ DI๋ฅผ ์ํ ๊ฐ์ฒด๋ค์ ์์ฑ์์ผ ๋๋ ๊ฒ์ด์๋ค๋ฉด, ์ด๊ฒ์ ์ข ๋ ๊ฐ๋จํ๊ฒ ํด์ module.provider(), module.factory(), module.value() ํํ๋ก๋ ์ฌ์ฉํ ์ ์๋ค. ์๋ ์ฝ๋๋ฅผ ์ดํด๋ณด๋๋ก ํ์.
// Using "provider" shortcut module.provider("di4", function(){ this.$get = function(){ return function(text) { return text; }; }; }); // Using "factory" shortcut module.factory("di5", function(){ return function(text) { return text; }; }); // Using "value" shortcut module.value("di6", function(text) { return text; });
์ฐจ์ด์ ์ ๋ฐ๊ฒฌํ ์ ์๋๊ฐ? ์ด๋ ๊ฒ ๋ง๋ค์ด ๋์ ๊ฐ์ฒด๋ค์ ๋ค์ ์ฝํธ๋กค๋ฌ๋ฅผ ์์ ํ์ฌ ์ ์ฉ์์ผ ๋ณด์.
module.controller("sampleController", function($scope, di1, d2, d3, d4, d5, d6) { $scope.text = "TEXT"; $scope.di1text1 = di1($scope, "DI1 TEXT 1"); $scope.di2text = di2("DI2 TEXT"); $scope.di3text = di3("DI3 TEXT"); $scope.di4text = di4("DI4 TEXT"); $scope.di5text = di5("DI5 TEXT"); $scope.di6text = di6("DI6 TEXT"); });
์ด๋ ๊ฒ ์ฝํธ๋กค๋ฌ๋ฅผ ์์ ํ ํ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด ์ด๋ป๊ฒ ๋ฌ๋ผ์ก๋์ง ํ์ธํ ์ ์์ ๊ฒ์ด๋ค. ๋ง์ง๋ง์ผ๋ก $injector ์๋น์ค๋ฅผ ์ด์ฉํ์ฌ DI๋ฅผ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ด๋ค. ์์ ์ฝํธ๋กค๋ฌ๋ฅผ ์๋์ ๊ฐ์ด ์์ ํ์.
module.controller("sampleController", function($scope, $injector, di1, d2, d3, d4, d5, d6) { $scope.text = "TEXT"; $scope.di1text1 = di1($scope, "DI1 TEXT 1"); $scope.di2text = di2("DI2 TEXT"); $scope.di3text = di3("DI3 TEXT"); $scope.di4text = di4("DI4 TEXT"); $scope.di5text = di5("DI5 TEXT"); $scope.di6text = di6("DI6 TEXT"); var di7 = $injector.get("di6") $scope.di7text = di7("DI7 TEXT"); });
์ด๋ ๊ฒ ์์ ํ ํ์ ๋ค์ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํด ๋ณด๋๋ก ํ์.
์ ๋ฆฌํ์๋ฉด, AngularJS์์ DI๋ ๋ค์ํ ๋ฐฉ๋ฒ โ ์ฌ๊ธฐ์๋ ์ด ์ผ๊ณฑ๊ฐ์ง ๋ฐฉ๋ฒ โ ์ผ๋ก ๊ตฌํ์ด ๊ฐ๋ฅํ๋ค. ๋ฐฉ๋ฒ์ ์๋ก ๋ค๋ฅด์ง๋ง ๋ชจ๋ ๋์ผํ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ ธ์จ๋ค. ๊ทธ ์ค์์ ๊ฐ์ฅ ๊ฐ๊ฒฐํ ๋ฐฉ๋ฒ์ module.value() ๋ฐฉ๋ฒ์ด๊ณ , ๊ฐ์ฅ ๋ณต์กํ ๋ฐฉ๋ฒ์ module.config()์ $provide ์๋น์ค๋ฅผ ์ด์ฉํ์ฌ provider ํ์ ์ ํธ์ถํ๋ ๊ฒ์ด๋ค. ๊ฐ๊ฒฐํ ์๋ก ๊ฐ๋ฐ์๊ฐ ์ฝํธ๋กคํด์ผ ํ๋ ๋ถ๋ถ์ด ์ค์ด๋ค๊ณ , ๋ณต์กํ ์๋ก ๊ฐ๋ฐ์๊ฐ ๊ด์ฌํด์ผ ํ๋ ๋ถ๋ถ์ด ๋์ด๋๋ค. ์๊ตฌ์ฌํญ์ ๋ณต์ก๋์ ๋ฐ๋ผ ์ ํํด์ ์ฌ์ฉํ๋ฉด ๋ ๊ฒ์ด๋ค.
์ด์์ผ๋ก ๊ฐ๋จํ๊ฒ AngularJS์์ DI๋ฅผ ํ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ํด ๋ ผ์ํด ๋ณด์๋ค. ์์ ์ฝ๋๋
http://jsfiddle.net/bluemood/QC9pW/
์ด๊ณณ์์ ํ ์คํธํด ๋ณผ ์ ์๋ค.
์ฐธ๊ณ :
https://github.com/angular/angular.js/wiki/Understanding-Dependency-Injection
์ ํ๋ธ ๋์์: http://youtu.be/1CpiB3Wk25U?t=37m
์ ๊ทํํ์ ์ฑ๋ฅ ํฅ์ ํ
๋ฐ์ดํฐ ์จ์ดํ์ฐ์ง์ ETL ํ๋ก์ธ์ค๋ ๋ฐ๋์ ํ์ํ๋ค. ์ด ๊ณผ์ ์์ ๋ฐ์ดํฐ ํด๋ ์ง์ ํฌํจํ ํ ์คํธ ํ๋ก์ธ์ฑ์ ์งํํ๊ฒ ๋๋๋ฐ, ์ ๊ทํํ์์ ์ด ํ ์คํธ ํ๋ก์ธ์ฑ์ ํต์ฌ ์์๋ค ์ค ํ๋์ด๋ค. ์ผ๋ฐ์ ์ธ ์ํฉ์์ ์ ๊ทํํ์์ ์๋์ ๊ฐ์ ํํ๋ก ์ฌ์ฉํ๋ค.
var value = "abcdefg"; var pattern = @"^abc"; if (Regex.IsMatch(value, pattern)) { Console.WriteLine("Match found"); }
์์ ์์ ์ ๊ฐ์ด ์ ๊ทํํ์์ ์ ์ ๋ฉ์๋์ธ Regex.Ismatch()์ ํํ๋ก ์ฐ์๋ค. ๋ฌผ๋ก ์๋์ ๊ฐ์ ํํ๋ก ์ฐ์ผ ์๋ ์๋ค.
var value = "abcdefg"; var pattern = @"^abc"; var regex = new Regex(pattern); if (regex.IsMatch(value)) { Console.WriteLine("Match found"); }
์์ ์์ ์ฝ๋๋ ์ ์ ๋ฉ์๋์ธ Regex.IsMatch()๋ฅผ ์ฌ์ฉํ๋ ๋์ Regex ์ธ์คํด์ค๋ฅผ ์ฌ์ฉํ๋ค. ๊ทธ๋ ๋ค๋ฉด ์ด ๋์ ์ฐจ์ด๋ ๋ฌด์์ผ๊น? ๋ฐ๋ก ์ฑ๋ฅ์ ์ฐจ์ด๋ผ๊ณ ํ ์ ์๋ค. ์ปดํ์ผ ์์ ์ ์ด๋ฏธ ์ ๊ทํํ์ ๊ฐ์ฒด๋ฅผ ํฌํจํ๊ณ ์๋๊ฐ, ๋ฐํ์ ์์ ์ ๊ทธ๋๊ทธ๋ ์ ๊ทํํ์ ๊ฐ์ฒด๋ฅผ ์ด๊ธฐํ ์์ผ ์ฌ์ฉํ๋๊ฐ์ ์ฐจ์ด๋ผ๊ณ ๋ ํ ์ ์๋๋ฐ, ์ผ๋ฐ์ ์ธ ์ฉ๋๋ก ์ฌ์ฉํ๋ค๋ฉด ๋ ๊ฐ์ง ๋ฐฉ๋ฒ๋ค ์ฌ์ด์๋ ํฐ ์ฐจ์ด๊ฐ ์๋ค. ํ์ง๋ง, ๋์ฉ๋์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋๋ฐ ์์ด์๋ ์กฐ๊ทธ๋งํ ์ฐจ์ด๊ฐ ์์ฒญ๋ ์ฑ๋ฅ์ ํฅ์ ํน์ ์ ํ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๋ค.
Regex.IsMatch() ๋ฉ์๋๋ ์ ์ ๋ฉ์๋๋ก์ ๋ด๋ถ์ ์ผ๋ก ์๋์ ๊ฐ์ ํํ๋ก ๊ตฌํ๋๋ค.
public static IsMatch(string input, string pattern) { var regex = new Regex(pattern); return regex.IsMatch(input); }
์ฆ, ์ ์ ๋ฉ์๋๋ฅผ ํธ์ถํ ๋๋ง๋ค Regex ์ธ์คํด์ค๊ฐ ๋ง๋ค์ด์ง๊ณ , ์ฐ์ด๊ณ , ์์ด์ง๊ธฐ๋ฅผ ๋ฐ๋ณตํ๋ค. ๋ฐ๋ผ์, ๋์ผํ ๋ฐ๋ณต์์ ์ ํ๋ ๊ฒฝ์ฐ ๋์ผํ Regex ์ธ์คํด์ค๋ฅผ ํ ๋ฒ ๋ง๋ค์ด๋๊ณ ์ฌํ์ฉ์ ํ๋ค๋ฉด ์์ฒญ๋ ์ฑ๋ฅ์ ํฅ์์ ๋ณผ ์ ์๋ค. http://www.dotnetperls.com/regex-performance ์์๋ ์ปดํ์ผ์ ํ๊ฒ ๋๋ค๋ฉด ๋๋ต 30%์ ์ฑ๋ฅ ํฅ์์ ๋ํ๋ธ๋ค๊ณ ํ๋ค.
๊ฐ๋ฐ์๋ค์ ์ธ๊ณ์์๋ If you are doing something repeatedly, you are doing it wrong ์ด๋ผ๋ ๊ธ์ธ์ด ์๋ค. ์ฆ, ๋ญ๊ฐ ๋์ผํ ์์ ์ ๋ฐ๋ณต์ ์ผ๋ก ํ๋ค๋ฉด, ๊ทธ๊ฑด ๋ญ๊ฐ ์๋ชป๋ ๊ฒ์ด๋ผ๋ ๊ฒ์ด๋ค. ๊ฒฐ๊ตญ ๊ทธ๋ถ๋ถ์์ ์ฑ๋ฅ ํฅ์์ ๊พํ ์ ์๋ค๋ ๋ง๊ณผ ๋์ผํ๋ค. ์์ ์ ๊ทํํ์ ์์ ๋ ๋ง์ฐฌ๊ฐ์ง๋ก, ๋์ผํ ์ ๊ทํํ์์ ์ฌ๋ฌ๋ฒ ์ฌ์ฉํ๋ค๋ฉด, ๊ทธ๊ฒ์ ๋ฏธ๋ฆฌ ์ปดํ์ผ์ ํด๋๊ณ ์ฌํ์ฉํ ์ ์๊ฒ๋ ํ๋ ๊ฒ์ด ์ฑ๋ฅ ํฅ์์ ์ ๋ฆฌํ๋ค๋ ๋ง๊ณผ ๋์ผํ๋ค.
์ฐธ์กฐ:
http://stackoverflow.com/questions/5854063/how-to-optimize-regular-expression-performance
http://stackoverflow.com/questions/414328/using-static-regex-ismatch-vs-creating-an-instance-of-regex
http://www.dotnetperls.com/regex-performance
http://blogs.msdn.com/b/bclteam/archive/2010/06/25/optimizing-regular-expression-performance-part-i-working-with-the-regex-class-and-regex-objects.aspx
http://blogs.msdn.com/b/bclteam/archive/2010/08/03/optimizing-regular-expression-performance-part-ii-taking-charge-of-backtracking.aspx
http://blogs.msdn.com/b/bclteam/archive/2011/03/28/optimizing-regex-performance-part-3-ron-petrusha.aspx

Anya is live and ready to show you everything. Watch her strip, dance, and perform exclusive shows just for you. Interact in real-time and make your fantasies come true.
Free to watch โข No registration required โข HD streaming
ASP.NET MVC 4 Web API ์์ null๊ฐ ํด๊ฒฐํ๊ธฐ
ASP.NET MVC 4 Web API๋ฅผ ์ฌ์ฉํ๋ฉด RESTful ์น์๋น์ค๋ฅผ ์์ฝ๊ฒ ํด๊ฒฐํ ์ ์๋ค. ๊ทธ๋ฐ๋ฐ, ๋ฌธ์ ๋ jQuery ๋๋ AngularJS ๊ฐ์ ์๋ฐ์คํฌ๋ฆฝํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํตํด AJAX ์ฝ์ ์ด์ฉํ์ฌ JSON ๋ฌธ์์ด์ Web API๋ก ๋๊ฒจ์ฃผ๊ฒ ๋๋ฉด, ํนํ POST ํน์ PUT ๋ฉ์๋์ ๊ฒฝ์ฐ, Web API ์ฝํธ๋กค๋ฌ์์ null๊ฐ์ผ๋ก ๋จ์ด์ง๋ ๊ฒฝ์ฐ๋ฅผ ๋ณด๊ฒ ๋๋ค.
์ด๊ฒ์ JSON ๋ฌธ์์ด์ ํ์ฑํ ๋ ํด๋น ์๋ฐ์คํฌ๋ฆฝํธ ํ๋ ์์์ด ๊ฐ๋ ํน์ง์ผ๋ก, ์ฝ๊ฐ์ ๋ถ๊ฐ์ ์ธ ์กฐ์น๋ฅผ ์ทจํด์ฃผ๋ฉด ํด๊ฒฐํ ์ ์๋ค.
var data = { "id": 1, "username": "abc", "email": "[email protected]" };
์์ JSON ๊ฐ์ฒด๋ฅผ jQuery AJAX ์ฝ์ ํตํด ์๋ฒ์ ์ ์กํ๋ ๊ฒฝ์ฐ์ AngularJS์ AjAX ์ฝ์ ํตํด ์๋ฒ์ ์ ์กํ๋ ๊ฒฝ์ฐ๋ฅผ ์ดํด๋ณด์.
// AJAX call using jQuery. $.ajax({ "type": "POST", "url": "/api/user", "dataType": "json", "data": JSON.stringify(data), "success": function(result) { // Do something } }); // AJAX call using AngularJS $http({ "method": "POST", "url": "/api/user", "data": JSON.stringify(data) }).success(function(result){ // Do something. });
Fiddler ๋๋ FireBug, ํฌ๋กญ ์น ๊ฐ๋ฐ์ ๋๊ตฌ ๋ฑ์ ํตํด AJAX ๋ฆฌํ์คํธ ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ฉด ์๋์ ๊ฐ๋ค.
{ "id": 1, "username": "abc", "email": "[email protected]" }
๊ทธ๋ฌ๋, ์ด ๋ฐ์ดํฐ๋ Web API ์ฝํธ๋กค๋ฌ๋ฅผ ํตํด ๋ณด๋ฉด null๊ฐ์ผ๋ก ์ ์ก์ด ๋๋ค.
public HttpResponseMessage Post([FromBody]string value) { // Do something. }
Web API ์ฝํธ๋กค๋ฌ์ Post ๋ฉ์๋๋ ๋๋ต ์์ ๊ฐ์ ํํ๊ฐ ๋ ํ ๋ฐ, ์ด ๋ value๊ฐ์ด null์ด ๋๋ ๊ฒ์ด๋ค. ๊ทธ ์ด์ ๋ JSON.stringify(data)๋ ๋ฐ์ดํฐ ์์ ๋ฐ๋์ =๊ฐ ์์ด์ผ ํ๋๋ฐ, ๊ทธ๊ฒ์ด ์๊ธฐ ๋๋ฌธ์ด๋ค. ์ด๊ฒ์ ํด๊ฒฐํ๊ธฐ ์ํด ๋ค์๊ณผ ๊ฐ์ด ์ฒ๋ฆฌํ๋ค.
// AJAX call using jQuery. $.ajax({ "type": "POST", "url": "/api/user", "dataType": "json", "data": { "": JSON.stringify(data) }, "success": function(result) { // Do something } });
jQuery ์์๋ key ๊ฐ์ด ์๋ JSON ๊ฐ์ฒด๋ก ํ ๋ฒ ๋ ๊ฐ์ธ์ฃผ๋ฉด ๋๋ค.
// AJAX call using AngularJS $http({ "method": "POST", "url": "/api/user", "data": "=" + JSON.stringify(data), "headers": { "Content-Type": "application/x-www-form-urlencoded" } }).success(function(result){ // Do something. });
AngularJS ์์๋ ๋จ์ํ =๋ฅผ ์์ ๋ถ์ฌ์ฃผ๊ณ , ํค๋์ Content-Type์ ๊ธฐ๋ณธ๊ฐ์ธ application/json์์ application/x-www-form-urlencoded์ผ๋ก ๋ฐ๊พธ์ด์ค๋ค. ๊ทธ๋ฆฌ๊ณ ๋์ ๋ค์ Web API๋ฅผ ํธ์ถํด ๋ณด๋ฉด ์ ์์ ์ผ๋ก JSON ์คํธ๋ง์ ๋ฐ์์ค๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
์ฐธ๊ณ : http://encosia.com/using-jquery-to-post-frombody-parameters-to-web-api
์ํฐํฐ ํ๋ ์์ํฌ Code First ๋ฐฉ๋ฒ๋ก #2
์ํฐํฐ ํ๋ ์์ํฌ Code First ๋ฐฉ๋ฒ๋ก #1
์ํฐํฐ ํ๋ ์์ํฌ Code First ๋ฐฉ๋ฒ๋ก #2
๋ฐ์ดํฐ ํ์ ์ค์ ํ๊ธฐ
์์ Local DB์ ํ ์ด๋ธ์ ์์ฑํ๋ ๋ฐฉ๋ฒ๊น์ง ์์ ๋ณด์๋ค. ๋ง๋ค์ด์ง ํ ์ด๋ธ์ ์๋์ ๊ฐ๋ค.
์ฌ๊ธฐ์ ๋์ฌ๊ฒจ ๋ด์ผ ํ ๊ฒ์ ๊ฐ๊ฐ์ ํ๋ ๋ฐ์ดํฐ ํ์ ๋ฐ ํฌ๊ธฐ์ด๋ค.
NULL vs NOT NULL
NVARCHAR(MAX)
decimal ๋ฐ์ดํฐ ํ์ ํฌ๊ธฐ
int, datetime
์์ ๊ธ์์ ์ธ๊ธํ ๋ฐ์ ๊ฐ์ด ์ํฐํฐ ์ด๋ฆ + Id ํํ์ ํ๋กํผํฐ๊ฐ ์์ ๊ฒฝ์ฐ ํด๋น ํ๋กํผํฐ๋ ์๋์ผ๋ก PK ์ฒ๋ฆฌ๊ฐ ๋๋ค. int, bool, DateTime ๊ฐ์ ๊ฒฝ์ฐ์๋ ๊ธฐ๋ณธ์ ์ผ๋ก Nullable ์์ฑ์ ๊ฐ๊ณ ์์ง ์์ผ๋ฏ๋ก ํ ์ด๋ธ ์์ฑ์์๋ ๋ง์ฐฌ๊ฐ์ง๋ก ์๋์ผ๋ก NOT NULL ์์ฑ์ ๊ฐ๋๋ค. ๋ฐ๋ฉด์ string ๋ฐ์ดํฐ ํ์ ์ ๊ฒฝ์ฐ์๋ NULL์ ํ์ฉํ๋ฏ๋ก ํ ์ด๋ธ ํ๋ ์ญ์ NULL๋ก ์ค์ ํ๋ค. ๋ง์ฝ int, bool, DateTime ๋ฐ์ดํฐ ํ์ ์ ๊ฐ๋ ํ๋์ NULL ๊ฐ์ ํ์ฉํ๋ ค๋ฉด ํ๋กํผํฐ ์ค์ ์ int?, bool?, DateTime?๊ณผ ๊ฐ์ ํํ๋ก Nullable ์์ฑ์ ์ถ๊ฐํด ์ฃผ๋ฉด ๋๋ค. ๋ํ ๋ท๋ท ์ฝ๋๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ ๋์ฝ๋๋ฅผ ์ง์ํ๋ฏ๋ก string ๋ฐ์ดํฐ ํ์ ์ ๊ณง๋ฐ๋ก nvarchar ํ์ ์ผ๋ก ๋์ํ๊ฒ ๋๋ค.
๊ทธ๋ ๋ค๋ฉด, ๋ฐ๋ก ์ด string ๋ฐ์ดํฐ ํ์ ์ ํฌ๊ธฐ๋ ์ด๋ป๊ฒ ์กฐ์ ์ ํ ๊น? ๋ณ๋ค๋ฅธ ์ค์ ์ด ์์ ๊ฒฝ์ฐ์๋ ๋ฌด์กฐ๊ฑด MAX๊ฐ์ ๊ฐ๋๋ฐ, ์ผ๋ฐ์ ์ผ๋ก ํ ์ด๋ธ์ ํ๋๋ nvarchar ํ์ ์ด๋ผ ํ๋๋ผ๋ ์ต๋ ํฌ๊ธฐ๋ฅผ ์ ํด๋๋๋ค. ์ด๋ ๊ฒ ๋ฐ์ดํฐ์ ํฌ๊ธฐ๋ฅผ ๊ฒฐ์ ํด์ฃผ๋ ๋ฐฉ๋ฒ์ ํฌ๊ฒ ๋๊ฐ์ง ๋ฐฉ์์ด ์๋ค.
Data Annotations
Fluent API
์ฌ๊ธฐ์๋ ๋จผ์ ์ฒซ๋ฒ์งธ Data Annotations ๋ฐฉ์์ ๋ค๋ฃจ๊ธฐ๋ก ํ๊ณ ๋ค์์ Fluent API๋ฅผ ๋ ผ์ํ๋๋ก ํ์.
Data Annotations
Data Annotation์ ์ํด์๋ ๊ฐ๊ฐ์ ํด๋ผ์ค๋ช ๋๋ ํ๋กํผํฐ๋ช ์ ์์ฑ ํด๋ผ์ค๋ฅผ ์ง์ ํด ์ค๋ค. ์์ ์์ฑํ๋ ์ํฐํฐ๋ค์ ์๋์ ๊ฐ์ด ๋ฐ๊พธ์ด ๋ณด๋๋ก ํ์.
[Table("ProductInfo")] public class Product { [Key] public int ProductId { get; set; } [Required(ErrorMessage="ProductName must be set")] [MaxLength(128, ErrorMessage="ProductName is too long")] [MinLength(4, ErrorMessage="ProductName is too short")] public string ProductName { get; set; } [Column(Name="Description", TypeName="NTEXT")] public string ProductDescription { get; set; } [NotMapped] public string ProductAlias { get; set; } [Required(ErrorMessage = "UnitPrice must be set")] public decimal UnitPrice { get; set; } [Required(ErrorMessage = "DateCreated must be set")] public DateTime DateCreated { get; set; } } public class Order { [Key] public int OrderId { get; set; } [Required(ErrorMessage = "DateOrdered must be set")] public DateTime DateOrdered { get; set; } [Required(ErrorMessage = "OrderBy must be set")] public int OrderBy { get; set; } } public class ProductOrder { [Key] public int ProductOrderId { get; set; } [Required(ErrorMessage = "ProductId must be set")] public int ProductId { get; set; } [Required(ErrorMessage = "OrderId must be set")] public int OrderId { get; set; } [Required(ErrorMessage = "AmountOrdered must be set")] public int AmountOrdered { get; set; } }
Data Annotation์ ์ํด์๋ ํฌ๊ฒ ๋๊ฐ์ง ์์ฑ ํด๋ผ์ค๊ฐ ์๋ค. ํ๋๋ Validation ์์ฑ ํด๋ผ์ค์ด๊ณ ๋ค๋ฅธ ํ๋๋ Annotation ์์ฑ ํด๋ผ์ค์ด๋ค. ์์ ์ฝ๋์์ Required, MaxLength, MinLength ๋ฑ๊ณผ ๊ฐ์ ์์ฑ ํด๋ผ์ค๋ค์ด Validation ์์ฑ ํด๋ผ์ค์ด๊ณ , Key, NotMapped, Table, Column ๋ฑ๊ณผ ๊ฐ์ ์์ฑ ํด๋ผ์ค๋ค์ ๊ฐ๋ฆฌ์ผ Annotation ์์ฑ ํด๋ผ์ค๋ผ๊ณ ๋ถ๋ฅธ๋ค. ์ด๋ฐ์๋ ๋ ๋ง์ ์์ฑ ํด๋ผ์ค๋ค์ด ์์ผ๋ ์์ธํ ์ฌํญ์ MSDN์ ์ฐธ๊ณ ํ๋๋ก ํ์.
์ด๋ ๊ฒ ์์ฑํด๋ผ์ค๋ค์ ์์ฑํ๊ณ ๋ ํ์ F5 ํค๋ฅผ ๋๋ฌ ํ ๋ฒ ๋๋ฒ๊น ์ ํ ํ MS SQL Server Management Studio๋ก ์ ์ํด์ ํ ์ด๋ธ ๊ตฌ์กฐ๋ฅผ ํ์ธํด ๋ณด๋ฉด ์๋์ ๊ฐ์ด ๋ณํ ๊ฒ์ ํ์ธํ ์ ์๋ค.
Products ํ ์ด๋ธ์ ์ด๋ฆ์ด ProductInfo๋ก ๋ฐ๋์๋ค
ProductName ์ปฌ๋ผ์ ๋ฐ์ดํฐ ํฌ๊ธฐ๊ฐ MAX์์ 128๋ก ๋ฐ๋์๋ค.
ProductDescription ์ปฌ๋ผ๋ช ์ด Description์ผ๋ก ๋ฐ๋์๋ค.
ProductDescription ๋ฐ์ดํฐ ํ์ ์ด NTEXT๋ก ๋ฐ๋์๋ค.
๋ค์์๋ ๊ฐ๊ฐ์ ํ ์ด๋ธ๋ง๋ค FK๋ฅผ ์ค์ ํ๋ ๋ฐฉ๋ฒ์ ๋ํด ๋ ผ์ํด ๋ณด๋๋ก ํ์.
์ํฐํฐ ํ๋ ์์ํฌ Code First ๋ฐฉ๋ฒ๋ก #1
์ํฐํฐ ํ๋ ์์ํฌ Code First ๋ฐฉ๋ฒ๋ก #1
์ํฐํฐ ํ๋ ์์ํฌ Code First ๋ฐฉ๋ฒ๋ก #2
์ํฐํฐ ํ๋ ์์ํฌ(Entity Framework, EF)๊ฐ ๊ฐ์ง ์๋ง์ ์ฅ์ ๋ค ์ค ํ๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ก๋ถํฐ ์ง์ ORM ๋งคํ ํด๋ผ์ค๋ฅผ ์์ฑํด ์ค๋ค๋ ๋ฐ ์๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ์ ์ํ ๋ก๊ทธ์ธ ์ ๋ณด๋ง ์ง์ ํด์ฃผ๋ฉด ํด๋น ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ชจ๋ ํ ์ด๋ธ, ์คํ ์ด๋ ํ๋ก์์ , ํจ์ ๋ฑ์ ๋ชจ๋ ๊ฐ์ฒดํํ์ฌ ์์ฝ๊ฒ ์ฝ๋์์ ์ฌ์ฉํ ์ ์๊ฒ ํด์ฃผ๋ ๊ฒ์ด๋ค. ํ์ง๋ง, ์ด ๋ฐฉ๋ฒ์ ๋ฌธ์ ์ ๋ค ์ค ํ๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์คํค๋ง๋ฅผ ๊ฐฑ์ ํ ํ EF์์ ํด๋น ๊ฐฑ์ ๋ด์ญ์ ์ ๋ฐ์ดํธํ๋ฉด, ์๋์ผ๋ก ์ค์ ํ ๋ถ๋ถ๋ค์ ๋ชจ๋ ์ฌ๋ผ์ง๊ฒ ๋๋ค. ๋ฐ๋ผ์, ์ด๋ฐ ๋ฌธ์ ์ ์ ํด๊ฒฐํ๊ธฐ ์ํด์๋ ๋ณดํต ๋๊ฐ์ง ๋ฐฉ๋ฒ ์ค ํ๋๋ฅผ ์ฌ์ฉํ๋ค.
partial ํด๋ผ์ค๋ฅผ ์ด์ฉํ์ฌ ์๋ ๋ณ๊ฒฝ ์ฌํญ ๋ถ๋ฆฌ์ํค๊ธฐ
EF Code FIrst ๋ฐฉ๋ฒ ์ ์ฉํ๊ธฐ
์ฌ๊ธฐ์๋ ๋๋ฒ์งธ Code First ๋ฐฉ๋ฒ์ ๋ํด ๋ ผ์ํด ๋ณด๊ณ ์ ํ๋ค. EF Code First ๋ฐฉ๋ฒ์ ๋ณดํต ์๋์ ๊ฐ์ ์์๋ฅผ ๊ฑฐ์ณ ์ ์ฉํ ์ ์๋ค.
๋ฐ์ดํฐ๋ฒ ์ด์ค Connection String ์ค์ ํ๊ธฐ
์ฐ์ web.config ํน์ app.config ํ์ผ์ <connectionStrings> ์น์ ์ ์๋์ ๊ฐ์ด ์์ฑํ๋ค.
<connectionStrings> <clear /> <add name="ApplicationDataContext" connectionString="Data Source=(LocalDB)\v11.0;Initial Catalog=ApplicationDatabase;Persist Security Info=True;Integrated Security=True;MultipleActiveResultSets=True;Connect Timeout=30" providerName="System.Data.SqlClient" /> </connectionStrings>
์์ ๋ด์ฉ์ Visual Studio 2012๋ถํฐ ์ฌ์ฉํ ์ ์๋ Local DB๋ฅผ ์ด์ฉํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๋ง๋๋ Connection String์ด๋ค. ์๋ฒ๋ช ์ (LocalDB)\v11.0, ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ช ์ ApplicationDatabase, ๊ทธ๋ฆฌ๊ณ Windows ํตํฉ ์ธ์ฆ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ ๊ฒ์ผ๋ก ์ค์ ํด ๋์๋ค. ์ด Connection String์ ์ข ๋ ๋ณด๊ธฐ ์ฝ๊ฒ ์ค์ ํ ์ถ๋ค๋ฉด GitHub์ ์ฌ๋ผ๊ฐ ์๋ ์คํ์์ค๋ค ์ค ํ๋์ธ Data Access Framework ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฐธ์กฐํ ์๋ ์๋ค.
DbContext ํด๋ผ์ค ์์ ๋ฐ๊ธฐ
Connection String ์ค์ ์ด ๋๋ฌ๋ค๋ฉด, ์๋ก์ด ApplicationDataContext ํด๋ผ์ค๋ฅผ ํ๋ ์์ฑํ๋ค. ์ด ํด๋ผ์ค๋ DbContext ํด๋ผ์ค๋ฅผ ์์๋ฐ์ ์ฌ์ฉํ๋ค.
public partial class ApplicationDataContext : DbContext { #region Constructors public ApplicationDataContext() : base("ApplicationDatabase") { ... } public ApplicationDataContext(string connectionString) : base (connectionString) { ... } #endregion }
์ด๋ ๊ฒ ์์ฑํ ApplicationDataContext๋ ์๋์ ๊ฐ์ด ์ฌ์ฉํ ์ ์๋ค.
using (var context = new ApplicationDataContext()) { ... }
Constructor ํ๋ผ๋ฏธํฐ ์์ด ์ง์ Context๋ฅผ ์์ฑํ๋ ๊ฒ๊ณผ, Connection String ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ์ ์์ฑํ๋ ๊ฒ, ์ด๋ ๊ฒ ๋๊ฐ์ง๊ฐ ์๋ค. ํ๋ผ๋ฏธํฐ ์์ด ์ง์ Context๋ฅผ ์์ฑํ๋ ๊ฒฝ์ฐ, ๋ํดํธ๋ก ApplicationDataBase๋ฅผ ์ด์ฉํ๋ค. ๋ง์ฝ, ์ง์ ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์๋ฒ์ ํด๋นํ๋ ์ด๋ฆ์ด ์์ ๊ฒฝ์ฐ ์๋กญ๊ฒ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์์ฑํ๊ฒ ๋๋ค.
public partial class ApplicationDataContext : DbContext { ... #region Properties public DbSet<Product> Products { get; set; } public DbSet<Order> Orders { get; set; } public DbSet<ProductOrder> ProductOrders { get; set; } #endregion }
์ํฐํฐ ์ถ๊ฐํ๊ธฐ
๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค์ ์ด ๋๋ฌ๋ค๋ฉด, ์ค์ ๋ก ์ฌ์ฉํ ํ ์ด๋ธ์ ์ง์ ํด ์ฃผ์ด์ผ ํ๋ค. ์์ ๊ฐ์ด Products ํ ์ด๋ธ๊ณผ Orders ํ ์ด๋ธ, ๊ทธ๋ฆฌ๊ณ ProductOrders ํ ์ด๋ธ์ด ์๋ค๊ณ ๊ฐ์ ํ๋ค๋ฉด ํด๋น ์ํฐํฐ ํด๋ผ์ค๋ฅผ ์๋์ ๊ฐ์ด ์ถ๊ฐํ๋ค.
public partial class Product { public int ProductId { get; set; } public string ProductName { get; set; } public string ProductDescription { get; set; } public decimal UnitPrice { get; set;} public DateTime DateCreated { get; set; } } public partial class Order { public int OrderId { get; set; } public DateTime DateOrdered { get; set; } public int OrderBy { get; set; } } public partial class ProductOrder { public int ProductOrderId { get; set; } public int ProductId { get; set; } public int OrderId { get; set; } public int AmountOrdered { get; set; } }
์ด๋ ๊ฒ Product, Order, ProductOrder ์ํฐํฐ๋ฅผ ์์ฑํ ํ F5 ํค๋ฅผ ๋๋ฌ ๋๋ฒ๊น ์ ํ ๋ฒ ์๋ํ๋ค. ๊ทธ๋ฆฌ๊ณ ๋์ Microsoft SQL Server Management Studio๋ฅผ ์ด์ฉํด LocalDB๋ก ์ ์ํด ๋ณด๋ฉด ์ค์ ๋ก ์๋ ๊ทธ๋ฆผ๊ณผ ๊ฐ์ด ApplicationDatabase ๋ฐ์ดํฐ๋ฒ ์ด์ค์ Products, Orders, ProductOrders ํ ์ด๋ธ์ด ๋ง๋ค์ด์ ธ ์๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
์ฌ๊ธฐ์ ์ฃผ๋ชฉํด์ผ ํ ๋ถ๋ถ์ด ํ๋ ์๋๋ฐ, ProductId, OrderId, ProductOrderId๋ ๋ชจ๋ ํน๋ณํ ์ค์ ์์ด๋ Primary Key๋ก ๋์ด ์๋ค. ์ด๋ ํด๋ผ์ค์ ์ด๋ฆ์ Id๊ฐ ๋ถ์ผ๋ฉด ์๋์ผ๋ก PK๋ก ์ธ์ํ๊ฒ๋ ํ๋ EF์ ์๋ ๋งคํ ๊ธฐ๋ฅ์ด๋ค.
๋ค์์๋ ์ด ์ํฐ๋ค ์ฌ์ด์ ๊ด๊ณ๋ฅผ ์ค์ ํ๋ ๊ฒ์ ๋ํด ๋ ผ์ํด ๋ณด๋๋ก ํ์.
Entity Framework ์ปค๋ฅ์ ์คํธ๋ง ๊ฐ๋ณ์ ์ผ๋ก ๊ตฌ์ฑํ๊ธฐ
Entity Framework (EF) ์ ๋ท๋ท ์ดํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ์ ์ฌ์ฉํ ์ ์๋ ORM ๋๊ตฌ๋ค ์ค ํ๋์ด๋ค. ๋ค๋ฅธ ORM ๋๊ตฌ๋ค์ ๋นํด ๋ฌ๋์ปค๋ธ๋ ์ ์ ๋ฟ ์๋๋ผ ์ฌ์ฉ์ด ๊ฝค ์ง๊ด์ ์ด๊ธฐ ๋๋ฌธ์ด๋ค. ๋ค๋ง, ํ๊ฐ์ง ๋ถํธํ ์ ์ด ์๋ค๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ปค๋ฅ์ ์คํธ๋ง์ด ๋๋ฌด ๊ธธ๋ค๋ ๊ฒ. ๋ณดํต web.config ํน์ app.config์ ๋ค์ด๊ฐ๋ EF ์ปค๋ฅ์ ์คํธ๋ง์ ๋๋ต ์๋์ ๊ฐ์ ํํ์ด๋ค.
<connectionStrings> <add name="ApplicationDataContext" connectionString="metadata=res://*/ApplicationDataContext.csdl|res://*/ApplicationDataContext.ssdl|res://*/ApplicationDataContext.msl;provider=System.Data.SqlClient;provider connection string="data source=(LocalDB)\v11.0;attachdbfilename=|Data Directory|AdventureWorks.mdf;UserId=username;Password=passwordintegrated security=False;connect timeout=30;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" /> </connectionStrings>
์ด๋ ๊ฒ ๋๋ฌด ์ปค๋ฅ์ ์คํธ๋ง ๋ถ๋ถ์ด ๋๋ฌด ๊ธธ๋ค๋ณด๋ ํ๋์ ๋ค์ด์ค์ง๋ ์์ ๋ฟ๋๋ฌ, ์ํฉ์ ๋ฐ๋ผ ์ ์ ํ๊ฒ ์๋ฒ๊ฐ ๋ฐ๋๋ค๊ฑฐ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ๋ฐ๋๋ค๊ฑฐ๋ ํ๋ ๊ฒฝ์ฐ์๋ ์์ ํ๊ธฐ๊ฐ ์ฝ์ง ์๋ค. ํ์ง๋ง, .edmx ํ์ผ์ ์ด์ฉํด EF๋ฅผ ๊ตฌ์ฑํ ๊ฒฝ์ฐ ์ธ ๊ฐ์ง์ ์๋ก ๋ค๋ฅธ ์ธ์๋ฅผ ๋ฐ์๋ค์ด๋ ์์ฑ์๊ฐ ์๊ธฐ๋๋ฐ, ๊ทธ์ค ํ๋๋ ์ด ์ปค๋ฅ์ ์คํธ๋ง์ ์ ์ฐํ๊ฒ ๊ตฌ์ฑํ ์ ์๋ ๋ฐฉ๋ฒ์ ์ ์ํ๋ค. ์๋๋ .edmx ํ์ผ์ ์ด์ฉํ์ฌ ์์ฑํ EF ๋ฐ์ดํฐ ์ฝํ ์คํธ์ ์์ฑ์๋ค์ด๋ค.
public partial class ApplicationDataContext : DbContext { // Initialises a new instance of the ApplicationDataContext object. public ApplicationDataContext() { ... } // Initialises a new instance of the ApplicationDataContext object // with the given connection string. public ApplicationDataContext(string connectionString) { ... } // Initialises a new instance of the ApplicationDataContext object // with the given entity connection instance. public ApplicationDataContext(EntityConnection conn) { ... } }
๋งจ ์๋ ์์ฑ์๋ฅผ ๋ณด๋ฉด EntityConnection ์ธ์คํด์ค๋ฅผ ์ธ์๋ก ๋ฐ์ EF ๋ฐ์ดํฐ ์ฝํ ์คํธ๋ฅผ ์์ฑํ๋ ๊ฒ์ ๋ณผ ์ ์๋ค. ๋ฐ๋ก ์ด ์์ฑ์๋ฅผ ์ด์ฉํ์ฌ ์ํฉ์ ๋ฐ๋ผ ์ ์ฐํ๊ฒ ์ปค๋ฅ์ ์คํธ๋ง์ ์์ฑํ ์ ์๋ค. ์๋ ์ฝ๋๋ ์ด ๋ฐฉ๋ฒ์ ์ด์ฉํ๋ ํ ์คํธ ์ผ์ด์ค ๋ฉ์๋์ด๋ค.
[Test] [TestCase("serverName", "dbName", "username", "password", "System.Data.SqlClient", true)] public void TestDatabaseConnection_SendParameters_GetDatabaseConnected(string serverName, string dbName, string username, string password, string provider, bool connected) { var sqlBuilder = new SqlConnectionStringBuilder(); sqlBuilder.DataSource = serverName; sqlBuilder.InitialCatalog = dbName; sqlBuilder.Username = username; sqlBuilder.Password = password; sqlBuiler.IntegratedSecurity = false; var efBuilder = new EntityConnectionStringBuilder(); efBuilder.Provider = provider; efBuilder.ProviderConnectionString = sqlBuilder.ToString(); efBuilder.MetaData = String.Format(@"res://*/{0}.csdl|res://*/{0}.ssdl|res://*/{0}.msl", "ApplicationDataContext"); using (var conn = new EntityConnection(efBuilder.ToString())) { conn.Open(); Assert.AreEqual(connected, conn.State == ConnectionState.Open); conn.Close(); } }
์์ ์ฝ๋์์ ์ ์ ์๋ค์ํผ,
SqlConnectionStringBuilder ์ธ์คํด์ค๋ฅผ ํตํด ๊ธฐ๋ณธ์ ์ธ ์ปค๋ฅ์ ์คํธ๋ง์ ๋ง๋ค๊ณ ,
๊ทธ๊ฒ์ ๋ค์ EntityConnectionStringBuilder ์ธ์คํด์ค๋ก ํ ๋ฒ ๋ ๊ฐ์ธ์ค ํ์,
์ด๊ฒ์ EntityConnection ๊ฐ์ฒด๋ก ๋ณด๋ด ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ปค๋ฅ์ ์ ์์ฑํ๋ค.
์ด๋ ๊ฒ ๋ง๋ค์ด์ง EntityConnection ์ธ์คํด์ค๋ ๋งจ ์์ ApplicationDataContext(EntityConnection conn) { ... } ์์ฑ์์ ์ธ์๋ก ์ฐ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํธ๋์ญ์ ์ ์ํ EF ์ธ์คํด์ค ์ด๊ธฐํ๋ฅผ ๊ฐ๋ฅํ๊ฒ ํ๋ค.
์์ ํ ์คํธ ์ฝ๋์์ ์ ์ ์๋ค์ํผ, web.config ๋๋ app.config ์ฌ์ฉ์ ๊ตณ์ด ๊ธฐ๋๊ธด ์ปค๋ฅ์ ์คํธ๋ง์ ์ฌ์ฉํ๋ ๊ฒ ๋ณด๋ค๋ ์๋ฏธ์๋ ๋ฐ์ดํฐ โ ์๋ฒ๋ช , DB๋ช , ์ ์ ๋ค์, ํจ์ค์๋ ๋ฑ โ ๋ฅผ <appSettings> ์น์ ์ ๋ฃ์ด๋๊ณ ๊ทธ๊ฒ์ ์ํฉ์ ๋ฐ๋ผ ๊ฐ๋ณ์ ์ผ๋ก ํธ์ถํ์ฌ ์ปค๋ฅ์ ์ ๋ง๋๋ ๊ฒ์ด ๊ฐ๋ฐ์ ๊ด์ ์์๋ ๋์ฑ ์์ํ ์ผ์ด ์๋๊น ํ๋ค.
์ฐธ์กฐ: EntityConnectionStringBuilder Class
CQRS ์ด๊ฐ๋จ ์ ๋ฆฌ
CQRS (Command Query Responsibility Segregation) ์ ์์๋ก ํ์ฅ์ด ์ฉ์ดํ ๋๊ท๋ชจ ์ํฐํ๋ผ์ด์ฆ ํ๊ฒฝ ํน์ ํด๋ผ์ฐ๋ ํ๊ฒฝ์์ ์ฌ์ฉํ๋ ์ํคํ ์ฒ ํจํด ์ค ํ๋.
์์ฃผ์์ฃผ ๊ฐ๋จํ ์ค๋ช ์ ์๋์ ๊ฐ๋ค.
In an oversimplified manner, CQRS separates commands (that change the data) from the queries (that read the data).
โ Rinat Abdullin from CQRS Starting Page
๊ฐ๋จํ๊ฒ ๋ฒ์ญ์ ํด๋ณด์๋ฉด
CRQS๋ (๋ฐ์ดํฐ๋ฅผ ๋ณ๊ฒฝํ๋) Command ๋ถ๋ถ์ (๋ฐ์ดํฐ๋ฅผ ์ฝ์ด๋ค์ด๋) Query ๋ก๋ถํฐ ๋ถ๋ฆฌ์ํจ๋ค
๋ผ๋ ๊ฒ์ด๋ค. ์์ธํ๊ฒ ๋ค์ด๊ฐ์๋ฉด ํ๋ ๋๋ ์์ง๋ง, ์ผ๋จ ์๋ฐ ๊ฒํฅ๊ธฐ ์์ผ๋ก ๊ฐ๋จํ ์ดํด๋ฅผ ํด๋ณด๋๋ก ํ์.
๋๋ถ๋ถ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํธ๋์ญ์ ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ก๋ถํฐ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด๋ค์ฌ ํ๋ฉด์ ๋ฟ๋ ค์ฃผ๋ ๊ฒ์ด๋ค. ์ด๋, ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๋ฐ์ดํฐ๋ฅผ ์ฝ๋ ์์ ๊ณผ ํ๋ฉด์ ๋ ๋๋ง์ ํ๋ ์์ ์ ๋ฐ๋์ ์ฐจ์ด๊ฐ ์๊ธฐ๊ธฐ ๋ง๋ จ์ด๋ฉฐ, ๋ ๋๋งํ๋ ๋ฐ์ดํฐ๋ ์ด๋ฏธ ์ค์ ๋ฐ์ดํฐ์๋ ์ฐจ์ด๊ฐ ์๊ธฐ๊ฒ ๋ง๋ จ์ด๋ค. CQRS ํจํด์ ์ด์ ์ ์ธ์ ํ๊ณ ์ฌ๊ธฐ์๋ถํฐ ์์ํ๋ค. ๋ฐ๋ผ์, ๊ตณ์ด ํ๋์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์์ CRUD์ R์ ํด๋นํ๋ ๊ธฐ๋ฅ๊ณผ ๋๋จธ์ง CUD ๊ธฐ๋ฅ์ ๊ณต์กด์ํค๋ ๊ฒ์ด ์๋ฏธ๊ฐ ์๋ค๋ ๊ฒ์ด ์ด ํจํด์ ํต์ฌ. ์ด์ฐจํผ R์ ๊ฒฐ๊ณผ๋ฌผ์ ์ ๋์ ์ฐจ์ด๋ ์์์ง์ธ์ ์ค์ ๋ฐ์ดํฐ์ ๋ค๋ฅด๋ ์บ์ฌ๋ก ๋๋ ค์ ๋์ฑ ๋น ๋ฅด๊ฒ ์ฌ์ฉ์๋ค์ด ์ฝ์ด๋ค์ผ ์ ์๋๋ก ํ๊ณ , CUD๋ ๋ฉ์์ง ํ๋ฅผ ํตํด ์ค์ ๋ฐ์ดํฐ๋ฅผ ๋ณ๊ฒฝ์ํค๊ณ , ๊ทธ ๋ณ๊ฒฝ์ด ์ผ์ด๋๋ ์์ ์ ์ด๋ฒคํธ๋ฅผ ๋ฐ์์์ผ์ ์บ์ฌ๋ฅผ ์ ๋ฐ์ดํธํ๋ ๋ฐฉ์์ผ๋ก ์งํํ์๋ ๊ฒ.
์ผ๋ฐ์ ์ธ ์์คํ ์์๋ ๊ตณ์ด CQRS ํจํด์ ์ ์ฉ์ํฌ ํ์ ๊น์ง๋ ์์ง๋ง, Windows Azure ๋ผ๋ ๊ฐ AWS ๊ฐ์ ํด๋ผ์ฐ๋ ๊ธฐ๋ฐ ์๋น์ค๋ฅผ ์ด์ฉํ๋ฉด์ Scalability๊ฐ ์์คํ ์ ํต์ฌ ์์๋ก ์์ฉํ ๋ ๋ฐ๋์ ๊ณ ๋ คํด์ผ ํ๋ ๊ฒ๋ค ์ค ํ๋.
CQRS ํจํด๊ณผ ๊ด๋ จํ ๋ด์ฉ์ ๊ฒ์๋ฅ๋ ฅ์ด ๋ธ๋ ค์ ๊ทธ๋ฐ์ง ํ๊ตญ์ด ๊ด๋ จ ๋ด์ฉ์ด ๊ฑฐ์ ์์ง ์ถ๋ค. ๊ฐ์ฅ ์ถ์ฒํ ๋งํ ๋งํฌ๋ ์ ์ธ์ฉ๊ตฌ๋ฌธ์ ๋น์ฌ์์ธ Rinat Abdullin์ด ์ด์ํ๋ ์น์ฌ์ดํธ์ CQRS ์น์ ์ธ CQRS Starting Page ์ด๊ณณ์ด๋ค. ๋ค๋ค ์ฌ๊ธฐ์๋ถํฐ ์ถ๋ฐ์ ์ ์ผ์ผ๋ผ๊ณ ์ถ์ฒํ๋๊ตฐ.
์ด์ธ์ ๋ค๋ฅธ ์ฝ์ด๋ณผ๋งํ ๋งํฌ๋ค์ ์๋์ ๊ฐ๋ค.
CQRS Starting Page
Clarified CQRS
CQRS on Windows Azure
CQRS Journey

Anya is live and ready to show you everything. Watch her strip, dance, and perform exclusive shows just for you. Interact in real-time and make your fantasies come true.
Free to watch โข No registration required โข HD streaming
์ ์ฐํ ์ฝ๋๋ฅผ ์ํด HttpContext ๋์ HttpContextBase ์ฌ์ฉํ๊ธฐ
๋ท๋ท ๊ธฐ๋ฐ ์น์ฌ์ดํธ ๊ฐ๋ฐ์ ํญ์ ์ฐ๋ ๊ฐ์ฒด๋ HttpContext ๊ฐ์ฒด์ด๋ค. ์๋ฒ ์์ฒญ, ์๋ฒ ์๋ต, ํ์ฌ ์ฌ์ฉ์, ์ธ์ , ์ฟ ํค ๋ฑ๋ฑ... ์ด HttpContext ๊ฐ์ฒด๊ฐ ๋ด๋นํ๋ ์ผ์ ๋ฌด๊ถ๋ฌด์งํ๋ค. ํ์ง๋ง, ์ด ๊ฐ์ฒด๋ HttpContext.Current์ ์ฑ๊ธํค ์ธ์คํด์ค๋ก๋ง ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ฐ, ์ด๊ฒ์ ๊ตฌ์ ํด๋ผ์ค(Concrete Class)์ฌ์ ๋จ์ ํ ์คํธ๋ฅผ ํ ๋์๋ ์ฌ์ฉ์ ํ ์๊ฐ ์๋ค. ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ณ ์ ๋ท๋ท ํ๋ ์์ 3.5๋ถํฐ ์๋กญ๊ฒ ๋ํ๋ ๊ฒ์ด ๋ฐ๋ก HttpContextBase๋ผ๋ ์ถ์ ํด๋ผ์ค(Abstract Class)์ด๋ค.
์ด HttpContextBase๋ผ๋ ์ถ์ ํด๋ผ์ค๋ฅผ ํตํด ๋จ์ ํ ์คํธ๋ผ๋ ๊ฐ ํ ์คํธ ์ฃผ๋ ๊ฐ๋ฐ ๋ฐฉ๋ฒ๋ก (TDD)์์ ์ฃผ๋ก ์ฌ์ฉํ๋ Mocking์ ์์ ๋กญ๊ฒ ๊ตฌํํ ์ ์๋ค. ์๋ ์ฝ๋๋ฅผ ๋ณด๋ฉด ๋๋ต์ ๊ฐ์ ์ก์ ์ ์์ ๊ฒ์ด๋ค.
HttpContextBase contextBase = new HttpContextWrapper(HttpContext.Current);
์์ ์์ ์ฝ๋๋ HttpContextWrapper ํด๋ผ์ค๋ฅผ ์ด์ฉํ์ฌ HttpContextBase ๊ฐ์ฒด๋ฅผ ๋ฆฌํดํ๋ ๊ฒ์ด๋ค. ์ค์ ๋์ํ๋ ์ฝ๋๋ ์ด๋ ๊ฒ ์์ฑํ ์ ์๊ณ , ๋จ์ ํ ์คํธ์์๋ ์๋์ ๊ฐ์ด ์์ฑํ ์๋ ์๋ค. Nunit๊ณผ NSubstitue๋ฅผ ์ฌ์ฉํ๋ค๊ณ ๊ฐ์ ํ์.
public class HomeControllerTest { private HttpContextBase _context; [SetUp] public void Init() { this._context = Substitute.For<HttpContextBase>(); ... } ... [Test] public void Test() { var controller = new HomeController(this._context); var result = controller.Index(); ... } }
์์ ํ ์คํธ ํด๋ผ์ค๋ฅผ ๋ณด๋ฉด HttpContextBase๋ฅผ mocking ํ์ฌ ์ฝํธ๋กค๋ฌ์ Dependency Injection์ ์ํค๋ ๊ฒ์ ๋ณผ ์ ์๋ค. ๋ง์ฝ Unity๋ผ๋ ๊ฐ Autofac ๊ฐ์ IoC ์ฝํ ์ด๋๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ค๋ฉด HttpContextBase์ญ์๋ ์ง์ ์ฌ์ฉํ๋ ๊ฒ๋ณด๋ค๋ IHttpContextBaseWrapper ๊ฐ์ ํํ๋ก ํ ๋ฒ ๋ ๊ฐ์ธ์ ์ฌ์ฉํ๋ฉด ๋๋ค.
์ฐธ๊ณ : HttpContext vs HttpContextBase vs HttpContextWrapper
ํฌ๋ก์ค ๋ธ๋ผ์ฐ์ง์ ์ํ HTML5 Boilerplate + ์ถ๊ฐ ์คํฌ๋ฆฝํธ
HTML5 Boilerplate (H5BP)๋ ํ๋ก ํธ์๋ ๊ฐ๋ฐ์๋ค์ด ์นํ์ด์ง๋ฅผ ์ ์ํ๋๋ฐ ํ์ํ ๋ฒ ์คํธ ํ๋ํฐ์ค๋ค์ ๋ชจ์๋์ ํ ํ๋ฆฟ์ด๋ค. ๋ค์ํ ๋ธ๋ผ์ฐ์ ํ๊ฒฝ, ํนํ ๊ตฌ๋ฒ์ ์ ์ธํฐ๋ท ์ต์คํ๋ก๋ฌ(IE)์์ HTML5 + CSS3 ์กฐํฉ์ ํ๋ถํ ๊ธฐ๋ฅ์ ์ด์ฉํ๊ธฐ๋ฅผ ์ํ๋ค๋ฉด ์ด H5BP์ ์ฌ์ฉ์ ํ์๋ถ๊ฐ๊ฒฐํ๋ค ํ ์ ์๋ค.
ํ์ง๋ง, H5BP๊ฐ ๋ง๋ฅ์ ์๋ ๊ฒ์ด, ๋ค์ํ ๋ธ๋ผ์ฐ์ ๋ฅผ ์ง์ํ๋ ์นํ์ด์ง๋ฅผ ์ ์ํ๋๋ฐ ๊ผญ ํ์ํ ์ต์ํ์ ์ฅ์น๋ค๋ง์ ํฌํจํ๊ณ ์๊ธฐ ๋๋ฌธ์ ๊ฐ๋ฐ ํ๊ฒฝ์ ๋ฐ๋ผ ๋ช๊ฐ์ง๋ฅผ ์ถ๊ฐํด์ผ ํ๋ ๊ฒ์ ๋ถ๋ช ํ๋ค. ๋ฐ๋ผ์, ์ด ํฌ์คํธ์์๋ H5BP์ ์ถ๊ฐ์ ์ผ๋ก ์ด๋ค ๊ฒ๋ค์ด ๋ ํ์ํ์ง์ ๋ํด ๋ ผ์ํด ๋ณด๊ธฐ๋ก ํ๋ค.
HTML ๋ฌธ์ ๊ธฐ๋ณธ ๊ณจ๊ฒฉ ๊ตฌ์กฐ
์ฐ์ , ๊ธฐ๋ณธ์ ์ธ H5BP์์ ์ ์ํ๋ HTML ๋ฌธ์์ ๊ณจ๊ฒฉ๊ตฌ์กฐ๋ถํฐ ์ดํด๋ณด์. ์๋์ ๋ด์ฉ์ H5BP ๋ฆฌํฌ์งํ ๋ฆฌ์ index.html์ด๋ค. (https://raw.github.com/h5bp/html5-boilerplate/master/index.html)
<!DOCTYPE html> <!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]--> <!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]--> <!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]--> <!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]--> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title></title> <meta name="description" content=""> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Place favicon.ico and apple-touch-icon.png in the root directory --> <link rel="stylesheet" href="css/normalize.css"> <link rel="stylesheet" href="css/main.css"> <script src="js/vendor/modernizr-2.6.2.min.js"></script> </head> <body> <!--[if lt IE 7]> <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p> <![endif]--> <!-- Add your site or application content here --> <p>Hello world! This is HTML5 Boilerplate.</p> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> <script>window.jQuery || document.write('<script src="js/vendor/jquery-1.10.2.min.js"><\/script>')</script> <script src="js/plugins.js"></script> <script src="js/main.js"></script> <!-- Google Analytics: change UA-XXXXX-X to be your site's ID. --> <script> (function(b,o,i,l,e,r){b.GoogleAnalyticsObject=l;b[l]||(b[l]= function(){(b[l].q=b[l].q||[]).push(arguments)});b[l].l=+new Date; e=o.createElement(i);r=o.getElementsByTagName(i)[0]; e.src='//www.google-analytics.com/analytics.js'; r.parentNode.insertBefore(e,r)}(window,document,'script','ga')); ga('create','UA-XXXXX-X');ga('send','pageview'); </script> </body> </html>
์งง์ ์ง์์ผ๋ก๋ <meta> ํ๊ทธ์ <link> ํ๊ทธ ๋ค์ ์์ฒด์ ์ผ๋ก ๋ซ๋ ํ๊ทธ๋ฅผ ๊ฐ๊ณ ์์ด์ผ ํ๋ ๊ฒ์ผ๋ก ์๊ณ ์๋ค. ๋ฐ๋ผ์, ์ด๋ถ๋ถ์ <meta ... />, <link ... /> ํํ๋ก ๋ฐ๊พธ์ด ์ฃผ๋ ๊ฒ์ด ์ข๋ค.
๊ธฐ๋ณธ ๋ฌธ์์
<meta charset="utf-8" />
์ ๋์ฝ๋ ๋ฌธ์์ ์ผ๋ก ์นํ์ด์ง๋ฅผ ์ ๊ณตํ๋ ๊ฒ์ด ์ข๋ค.
IE ํธํ์ฑ ๋ชจ๋ ๋ฉํ ํ๊ทธ
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
์ด ๋ด์ฉ์ ์ฌ์ฉ์๊ฐ IE๋ฅผ ์ฌ์ฉํด์ ํ์ด์ง๋ฅผ ์ด์์ ๋, ํด๋น IE๊ฐ ์ง์ํ ์ ์๋ ์ต์ ์ ํธํ์ฑ ๋ชจ๋๋ก ํ์ด์ง๋ฅผ ๋ ๋๋งํ๊ฒ๋ ํ๋ ๊ฒ์ด๋ค. ํ์ง๋ง, ์ด ๋ฉํ ํ๊ทธ๋ ์ธํธ๋ผ๋ท ์์์๋ ํด์ํ ์๊ฐ ์๊ธฐ ๋๋ฌธ์ ์น์๋ฒ์์๋ ์์ฒด์ ์ผ๋ก ์ปค์คํ ํค๋ ์์ ์์ ํธํ์ฑ ๋ชจ๋๋ฅผ ๋ฟ๋ ค์ฃผ๋ ๊ฒ์ด ์ข๋ค. ์ด์ ๋ง๋ถ์ฌ ๋ง์ฝ ์ฌ์ฉ์๊ฐ IE ํฌ๋กฌ ์ต์คํ ์ ์ ์ฌ์ฉํ ๊ฒฝ์ฐ์๋ ์๋์ ๊ฐ์ด ์์ ํ์ฌ ํฌ๋กฌ ์ต์คํ ์ ์ผ๋ก ๋ ๋๋งํ๋ ๊ฒ์ ๊ฐ์ ํ๊ฒ๋ ํ ์๋ ์๋ค.
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
ํ๋น์ฝ
๋ค์ํ ์ฌ์ด์ฆ์ ํ๋น์ฝ์ ์ค๋นํด ๋๋ฉด ๋ค์ํ ๋๋ฐ์ด์ค์์ ํ๋น์ฝ๋ค์ ๋ชจ์์ด ๊นจ์ง๋ ํ์์ ๋ฐฉ์งํ ์ ์๋ค. H5BP์ ๋ชฉ์ ์ ๋ง๊ฒ๋ ๋ค์ํ ์ฌ์ด์ฆ์ ํ๋น์ฝ์ ์์ฑํด ์ฃผ๋ ์ฌ์ดํธ๋ http://iconifier.net๊ณผ ๊ฐ์ ๊ฒ๋ค์ด ์๋ค.
CSS ์ ๊ทํ
<link rel="stylesheet" href="css/normalize.css" />
์น๋ธ๋ผ์ฐ์ ๋ค๋ง๋ค ์ ๋ง๋ค์ ๋ฐฉ์์ผ๋ก ๊ธฐ๋ณธ ๋ ๋๋ง ๋ชจ๋๋ฅผ ์ ๊ณตํ๊ณ ์๋ค. ๋ฐ๋ผ์, ๊ฐ๊ธ์ ์ด๋ฉด ๋ธ๋ผ์ฐ์ ๊ณ ์ ์ ๋ ๋๋ง ๋ชจ๋ ๋์ ์ด๋ ๊ฒ ์ ๊ทํ์ํจ CSS๋ฅผ ์ด์ฉํ์ฌ ๋ธ๋ผ์ฐ์ ์ ์๊ด์์ด ๋์ผํ ๋ ๋๋ง์ ์ ๊ณตํ๋ ๊ฒ์ด ์ข๋ค. ์ฐธ๊ณ ๋ก, ํธ์ํฐ ๋ถํธ์คํธ๋ฉ๊ณผ ๋์์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ์๋ ์ด๋ฏธ ๋์ผํ ๋ด์ฉ์ ์ ๊ทํ CSS๊ฐ ๋ค์ด ์๊ธฐ ๋๋ฌธ์ ํ์์๋ค.
Modernizr โ HTML5 ์๋ฆฌ๋จผํธ ํด๋ฆฌํ
IE8 ์ดํ ๋ฒ์ ์์๋ HTML5์์ ์๋กญ๊ฒ ์ ๊ณตํ๋ ํ๊ทธ๋ค์ ์ธ์ํ ์ ์๋ค. ๋ฐ๋ผ์, ์ด๋ฅผ ์ธ์์ํค๋ ์์ ์ด ํ์ํ๋ฐ, ์ด๊ฒ์ ์ด modernizr๊ฐ ๋ด๋นํ๋ค. html5shiv.js๋ก๋ ์ถฉ๋ถํ ๊ฐ๋ฅํ์ง๋ง, modernizr๋ ์ด๋ฅผ ํฌํจํ ๋ค์ํ ๊ธฐ๋ฅ๋ค์ ํฌํจํ๊ณ ์์ผ๋ฏ๋ก ์ด๊ฒ์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค. ์ฐธ๊ณ ๋ก, modernizr๋ <head> ํ๊ทธ ์์์ ๋ก๋ฉํ๋ ์ ์ผํ(?) ์๋ฐ์คํฌ๋ฆฝํธ์ด๋ค.
์ด์์ผ๋ก H5BP์์ ์ ๊ณตํ๋ ํ ํ๋ฆฟ์ ๋ํด ๊ฐ๋ตํ๊ฒ ํ์ธํด ๋ดค๋ค. ์ด์ด์ ์๋์ ์ธ๊ธํ๋ ๋ถ๋ถ์ H5BP์ ๋ถ๊ฐ์ ์ผ๋ก ์ถ๊ฐํ๋ฉด ์ข์ ๋ด์ฉ๋ค์ด๋ค.
jQuery
์๋ฐ์คํฌ๋ฆฝํธ ํ๋ ์์์ ๋ํ์ฃผ์. ๊ตณ์ด ์์ด๋ ๊ด์ฐฎ์ง๋ง, ์ด์ง๊ฐํ๋ฉด ๋ก๋ํ๋ ๊ฒ์ด ์ข๋ค. IE9 ์ดํ ๋ฒ์ ์ ์ง์ํ๊ธฐ ์ํด์๋ jQuery 1.x ๋ฒ์ ์ ์ฌ์ฉํ๋ค. ๋ง์ฝ ํธ์ํฐ ๋ถํธ์คํธ๋ฉ์ ์ฌ์ฉํ๋ค๋ฉด, jQuery ๋ก๋ฉ์ ํ์.
Placeholders.js
IE9 ์ดํ์ ๋ธ๋ผ์ฐ์ ์์๋ HTML5์์ ์๋กญ๊ฒ ์ ๊ณตํ๋ <input> ํ๊ทธ์ placeholder๋ฅผ ์ ๋๋ก ์ธ์ํ์ง ๋ชปํ๋ค. ์ด๋ฅผ ์ํด Placeholders.js(http://jamesallardice.github.io/Placeholders.js) ๋ผ๋ ํด๋ฆฌํ์ ๋ก๋ํ๋ค. ์ด์ ๋๋ถ์ด Placeholders.js์ ๊ธฐ๋ฅ์ ๋ณด์ํด์ฃผ๋ Placeholders.js Monkey Patch(https://github.com/aliencube/Placeholders.js-Monkey-Patch)๋ ํจ๊ป ๋ก๋ํ๋ค. ์ฐธ๊ณ ๋ก Placeholders.js Monkey Patch๋ jQeury๊ฐ ์์ด์ผ๋ง ์คํ ๊ฐ๋ฅํ๋ค.
EcmaScript 5 ์ง์
<!--[if lte IE 8]> <script type="text/javascript" src="js/es5-shim.min.js"></script> <![endif]-->
IE8์์ ์ฌ์ฉํ๋ ์๋ฐ์คํฌ๋ฆฝํธ ์์ง์ ์ค๋๋ ๊ฒ์ด๋ผ์ EcmaScript 5๋ฅผ ์ง์ํ์ง ๋ชปํ๋ค. EcmaScript 5์์๋ Array์ ๊ด๋ จํด์ ํฅ์๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ฏ๋ก ์ด๋ฅผ ์ธ์์์ผ์ฃผ๋ ํ์ฅ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ํ์ํ๋ฐ, ์ด ๋ es5-shim.js(https://github.com/kriskowal/es5-shim)๊ฐ ํ์ํ๋ค.
linq.js
<script type="text/javascript" src="js/linq.min.js"></script>
๋ง์ฝ .NET์ LINQ์ ์ต์ํ๋ค๋ฉด linq.js(http://linqjs.codeplex.com)๋ฅผ ์ค์นํด ๋ณด๋ ๊ฒ๋ ์ข๋ค.
์ด์์ผ๋ก H5BP ํ ํ๋ฆฟ์ ๋ง๋ถ์ฌ ํจ๊ป ์ฌ์ฉํ๋ฉด ์ข์๋งํ ์๋ฐ์คํฌ๋ฆฝํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ ๋์ดํด ๋ดค๋ค. ์ด๋ ๋ฌผ๋ก ์ต์ํ์ผ๋ก ํ์ํ ๊ฒ๋ค์ด๊ณ ํ๋ก์ ํธ์ ์ฑ๊ฒฉ๋ง๋ค ๋ ๋ง์ ๊ฒ๋ค์ ์ถ๊ฐํ ์ ์์ ๊ฒ์ด๋ค.
Placeholders.js Monkey Patch ํด์ค
์ด์ ๊ธ์ธ IE8 ์์ input ํ๊ทธ์ textarea ํ๊ทธ์ placeholder ์์ฑ ์ ์ฉํ๊ธฐ์์ Placeholders.js๋ฅผ ์ด์ฉํ๋ฉด jquery.placeholder ํ๋ฌ๊ทธ์ธ๋ณด๋ค ์ฌ๋ฌ๋ชจ๋ก ์ฌ์ฉ์ด ํธ๋ฆฌํ๋ค๊ณ ์ธ๊ธํ ์ ์ด ์๋ค.
๊ทธ๋ฐ๋ฐ, ์ด Placeholderes.js ์ญ์๋ ๋ค๋ฅธ DOM ์๋ฆฌ๋จผํธ๋ค์ ์ด๋ฒคํธ๋ค์์๋ ๊ธฐ๋ํ๋ ๋๋ก ์๋ํ์ง ์๋ ๊ฒฝ์ฐ๊ฐ ์๋ค. ์ด๋ฐ ๊ฒฝ์ฐ๋ฅผ ๋ณด์ ํ๊ธฐ ์ํด์ Placeholders.js Monkey Patch๋ฅผ ๋ง๋ค์ด์ ๋ฐฐํฌํ๊ฒ ๋๋ค. Placehoders.js๋ ๋ชจ๋ input:text ์๋ฆฌ๋จผํธ์ textarea ์๋ฆฌ๋จผํธ์ ๋ช๊ฐ์ง ๋นํ์ค ์์ฑ์ ์ถ๊ฐํ๋ ํด๋ฆฌํ (polyfill) ํํ๋ก ์ด๋ฃจ์ด์ง๋ค. ๊ทธ์ค์ ๋ช๊ฐ์ง ์๋ฅผ ๋ค์๋ฉด ์๋์ ๊ฐ์ ๊ฒ๋ค์ด ์๋ค.
data-placeholder-value
data-placeholder-active
data-placeholder-bound
์ด ์ธ๊ฐ์ง๊ฐ input:text ์๋ฆฌ๋ฉํธ์ ์ฐ์ด๋ ๋ํ์ ์ธ ํด๋ฆฌํ ์์ฑ๋ค์ด๋ค. IE8์์ Placeholders.js๋ฅผ ์ ์ฉํ ํ์ด์ง๋ฅผ ์ด์ด๋ณด๋ฉด ์๋์ ๊ฐ์ ํํ๋ก ๋ณด์ด๋ ๊ฒ์ ์ ์ ์๋ค.
<input type="text" id="username" class="placehldersjs" name="username" placeholder="Username" data-placeholder-value="Username" data-placeholder-bound="true" data-placeholder-active="true" value="Username" />
Placeholders.js๋ placeholder ์์ฑ์ ์ฌ์ฉํ ์ ์๊ธฐ ๋๋ฌธ์, placeholder ์์ฑ๊ฐ์ ๋์ value ์์ฑ๊ฐ์ ๋ฃ์ด์ฃผ๊ณ , ๊ทธ๊ฒ์ placeholdersjs ๋ผ๋ CSS ํด๋ผ์ค๋ฅผ ์ด์ฉํด ์์์ ์กฐ์ ํ๋ค. placeholdersjs ํด๋ผ์ค์ ๊ธฐ๋ณธ๊ฐ์ #ccc์ด๋ค. ๋ฌผ๋ก ํด๋นํ๋ input ์๋ฆฌ๋จผํธ์ ์ด๋ฏธ ๊ฐ์ด ์๋ค๋ฉด ์๋์ ๊ฐ์ ํํ๋ก ๋ํ๋๊ฒ ๋๋ค.
<input type="text" id="username" name="username" placeholder="Username" value="joebloggs" />
๊ทธ๋ฐ๋ฐ, ๋ฌธ์ ๋ ๋ค๋ฅธ DOM ์๋ฆฌ๋จผํธ๋ค๊ณผ ์ํธ์์ฉ์ ํ๋ฉด์ ์ด ํด๋ฆฌํ๋ค์ด ์ ๋๋ก ์๋์ ํ์ง ์๋ ๊ฒฝ์ฐ๊ฐ ์๋ค. ์๋ฅผ ๋ค์ด์ ๋๋กญ๋ค์ด๋ฆฌ์คํธ์์ ๊ฐ์ ๋ฐ๊ฟ ๋์ ๊ฐ์ ํ์๋ค์ด ๋ฐ๋ก ๊ทธ๊ฒ์ธ๋ฐ, ๊ทธ๋ด ๋ ์ด ๋ชฝํค ํจ์น๊ฐ ์ญํ ์ ํ๊ฒ ๋๋ค. ์ผ๋ฐ์ ์ผ๋ก ์ด Placeholders.js ์๋ฐ์คํฌ๋ฆฝํธ๋ IE9 ์ดํ์์๋ง ์ ์ฉ์ํค๋ฉด ๋๊ธฐ ๋๋ฌธ์ ์๋์ ๊ฐ์ ํํ๋ก ํธ์ถํ๋ค.
<!--[if lte IE 9]> <script type="text/javascript" src="js/Placeholders.min.js"></script> <![endif]-->
๋ง์ฐฌ๊ฐ์ง๋ก ๋ชฝํค ํจ์น ์ญ์๋ ์๋์ ๊ฐ์ ํํ๋ก ํธ์ถ์ ํ๋ฉด ๋ค๋ฅธ ๋ธ๋ผ์ฐ์ ํน์ IE10 ์ด์์์๋ ์ํฅ์ ๋ฐ์ง ์๋๋ค.
<!--[if lte IE 9]> <script type="text/javascript" src="js/jquery.Placeholders.monkey.patch.js"></script> <![endif]-->
input:text์ textarea ์๋ฆฌ๋จผ์ค ์์ฑ ์ฌ์ค์
์ด๋ ๊ฒ ํธ์ถ์ ํด๋์ ์ํ์์๋ ๋ชฝํคํจ์น์์ ์ ์ธํ ํจ์๋ค์ ์ค๋ก์ง IE9 ์ดํ์์๋ง ์ฌ์ฉํ ์ ์๊ฒ ๋๋ค. ๋ชฝํค ํจ์น์์ ์ ์ธํ ํจ์๋ค์ Placeholders.js์์ ์ ์ํ ์์ฑ๊ณผ CSS ํด๋ผ์ค๊ฐ ์ ๋๋ก ์๋ํ๊ณ ์๋์ง ๊ฒ์ฆํ๋ ์ญํ ์ ํ๋ค. ์๋ฅผ ๋ค์ด #select-box๋ผ๋ id ๊ฐ์ ๊ฐ๋ ๋๋กญ๋ค์ด๋ฆฌ์คํธ๊ฐ ์๋ค๊ณ ๊ฐ์ ์ ํ ๋ $("#select-box").change() ๋๋ $("#select-box").click()์ ์ฝ๋ฐฑ ํจ์๋ฅผ ์ด์ฉํ์ฌ ๊ฒ์ฆ์ ํ๋ ๊ฒ์ด๋ค.
$("#select-box").change(function () { if (typeof (applyPlaceholderAttributes) == typeof (Function)) { $("input:text, textarea").each(function () { applyPlaceholderAttributes($(this)); }); } });
์ด๋ฐ ์์ผ๋ก applyPlaceholderAttributes() ํจ์๋ฅผ ํธ์ถํ๋ฉด ์์์ ๋ณด์ ์ ํด์ค๋ค. ์ฌ๊ธฐ์ if (typeof(applyPlaceholderAttributes) == typeof(Function)) { ... } ๋ธ๋ก์ IE9 ์ดํ์์ ์ด ๋ชฝํค ํจ์น๋ฅผ ๋ก๋ํ์ ๊ฒฝ์ฐ์๋ true, ์๋๋ฉด false ๊ฐ์ ๊ฐ๋๋ค.
๋ง์ฝ ์กฐ๊ธ ๋ ๊ตฌ์ฒด์ ์ผ๋ก input ์๋ฆฌ๋จผํธ๋ค์ ๋ฒ์๋ฅผ ์ง์ ํ๊ณ ์ถ๋ค๋ฉด ๋ชฝํค ํจ์น๋ฅผ ํธ์ถํ ๋ ์๋์ ๊ฐ์ ํํ๋ก ํธ์ถํ๋ฉด ๋๋ค.
<!--[if lte IE 9]> <script type="text/javascript" src="js/jquery.Placeholders.monkey.patch.js"></script> <script type="text/javascript"> Placeholders.For = { "inputs": ["input:text", "textarea"], "fakePasswords": ["#fake-password"], "forms": ["form"] }; </script> <![endif]-->
Placeholders.For ๋ผ๋ JSON ๊ฐ์ฒด๋ฅผ ์ ์ธํด์ input ์๋ฆฌ๋จผํธ๋ค์ ๋ฒ์๋ฅผ ์ ํ ์ ์๋ค. ๊ทธ๋ ๊ฒ ํ ํ ๋๋กญ๋ค์ด๋ฆฌ์คํธ์ ์ด๋ฒคํธ ์ญ์๋ ์๋์ ๊ฐ์ด ์ด์ง ๋ฐ๊ฟ์ฃผ๋ฉด ๋.
if (typeof (applyPlaceholderAttributes) == typeof (Function)) { $.each(Placeholders.For.inputs, function (i, element) { $(element).each(function () { applyPlaceholderAttributes($(this)); }); }); }
input:password ์์ฑ ์ฌ์ค์
Placeholders.js์ ๊ฐ์ฅ ์น๋ช ์ ์ธ ๋จ์ (?)์ IE8 ์ดํ์์๋ ํจ์ค์๋ ํ๋๊ฐ placeholder ๊ฐ์ด ๋ณด์ด์ง ์๊ณ ********์ ๊ฐ์ด ์ค์ ๋ก ํจ์ค์๋๋ฅผ ์ ๋ ฅํ ๊ฒ์ฒ๋ผ ๋ณด์ธ๋ค๋ ๊ฒ์ด๋ค. IE9 ์ด์์์๋ input ์๋ฆฌ๋จผํธ์ type ์์ฑ์ ๋ฐ๊ฟ ์ ์์ด์ Placeholders.js ๋ด๋ถ์ ์ผ๋ก password ํ์ ์์ text ํ์ ์ผ๋ก ๋ฐ๊พธ์ด์ placeholder ์์ฑ๊ฐ์ ๋ณด์ฌ์ฃผ๋ค๊ฐ ์ค์ ํจ์ค์๋ ์ ๋ ฅ์ ์ํด ํฌ์ปค์ค๋ฅผ ์ด๋์ํค๋ฉด ๋ค์ text ํ์ ์์ password ํ์ ์ผ๋ก ๋ฐ๊พธ๋ ๊ธฐ๋ฅ์ ํ๋ค.
ํ์ง๋ง, IE8 ์ดํ์์๋ ์ด๋ ๊ฒ type์ ๋ฐ๊ฟ ์ ์๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ด ๋ถ๊ฐ๋ฅํ๋ค. ๋ชฝํค ํจ์น๋ IE8์ ์ํด #fake-password๋ผ๋ ํ ์คํธ ํ๋๋ฅผ ์ค๋นํด ๋๊ณ ์ฌ์ฉ์๊ฐ ํจ์ค์๋ ์ ๋ ฅ์ ์ํด ํฌ์ปค์ค๋ฅผ ์ด๋์ํค๋ฉด ์๋ ํจ์ค์๋ ํ๋๋ฅผ ๋ณด์ฌ์ฃผ๊ณ , ํฌ์ปค์ค๋ฅผ ๋ฒ์ด๋๋ฉด ํจ์ค์๋ ํ๋๋ฅผ ๊ฐ์ถ๊ณ fake password ํ๋๋ฅผ ๋ณด์ฌ์ฃผ๋ ํ์์ผ๋ก ์ฒ๋ฆฌํ๊ฒ๋ ํ๋ค. ๋ฌผ๋ก , ์ด๋ฅผ ์ํด ๋ค์๊ณผ ๊ฐ์ ๋ถ๊ฐ์ ์ธ ๋งํฌ์ ์ด ํ์ํ๋ค.
<!--[if lte IE 8]> <input type="text" id="fake-password" name="fake-password" placeholder="Password" data-placeholder-password="password" required="required" style="display: none;" /> <![endif]-->
์ด๋ ๊ฒ ํด๋์ผ๋ฉด IE8 ์ดํ์ ๋ธ๋ผ์ฐ์ ์์๋ง ์์ ๋ด์ฉ์ ๋ก๋ํ๊ฒ ๋๊ณ ์ด๊ฒ์ด ๊ธฐ์กด์ ํจ์ค์๋ ํ๋๋ฅผ ๋์ฒดํ๋ ์ญํ ์ ํ๋ค,
form ์ ์ก
Placeholders.js์ ์น๋ช ์ ์ธ ๋ฌธ์ ์ ๋ค ์ค ํ๋๋ input ์๋ฆฌ๋จผํธ์ value ์์ฑ์ ์ด์ฉํ๋ค๋ณด๋, ์๋ฒ๋ก ์ด placeholder ๊ฐ๋ค์ ์ ์กํ๋ค๋ ๊ฒ์ ์๋ค. ๋ฐ๋ผ์, ํผ ์ ์ก ์ง์ ์ ์ด๋ฌํ ๋ถํ์ํ placeholder ๊ฐ๋ค์ ์ ๊ฑฐํ ํ์๊ฐ ์๋ค. ์ฌ์ค, ์ด๋ถ๋ถ์ Placeholders.For JSON ๊ฐ์ฒด์ ์ ์ฉ์ํค๊ณ ์ ํ๋ form ์๋ฆฌ๋จผํธ๋ค์ ์ง์ ํด ๋์ผ๋ฉด ์์์ ๋ถํ์ํ ๊ฐ๋ค์ ๊ฑท์ด๋ด ์ค๋ค.
์ด๋ ๊ฒ Placeholders.js Monkey Patch์ ์๋์๋ฆฌ์ ๋ํด ๊ฐ๋จํ๊ฒ ์ค๋ช ์ ํด ๋ณด์๋ค.
๋ท๋ท์ LINQ ๊ธฐ๋ฅ์ ์๋ฐ์คํฌ๋ฆฝํธ๋ก ์ด์ฉํ๊ธฐ
LINQ (Language Integrated Query)๋ ๋ท๋ท ๊ฐ๋ฐ์ ๊ฐ์ฅ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ๋ค ์ค์ ํ๋์ด๋ค. LINQ-to-SQL, LINQ-to-XML, LINQ-to-OBJECT ๋ฑ ๊ฑฐ์ ๋ชจ๋ ์ํฉ์์ LINQ๋ฅผ ์ฌ์ฉํ ์ ์๋ค. LINQ๋ ๋ณดํต ์๋์ ๊ฐ์ ํํ๋ก ๋ง์ด ์ฐ์ธ๋ค.
var products = (from p in context.Products where p.ProductName.Contains("ABC") select p).ToList();
๋๋
var products = context.Products .SingleOrDefault(p => p.ProductId == 123);
ํ์ง๋ง ์ด๊ฒ์ ๊ฐ์ฅ ํฐ ๋จ์ (?)์ด๋ผ๋ฉด, ํ๋ก ํธ์๋์์ ์ฐ์ด๋ ์๋ฐ์คํฌ๋ฆฝํธ๋ก๋ ์ด๋ฌํ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์๋ค๋ ๋ฐ ์๋ค. ๊ทธ๋์ ๋ํ๋ ๊ฒ์ด ๋ฐ๋ก linq.js์ด๋ค.
linq.js ์๊ฐ
์ด ์๋ฐ์คํฌ๋ฆฝํธ ํ๋ ์์์ ์ฌ์ฉํ๋ฉด, LINQ์์ ์ ๊ณตํ๋ ๋๋ถ๋ถ์ ๊ธฐ๋ฅ๋ค์ ์๋ฐ์คํฌ๋ฆฝํธ ์์์๋ ๊ฑฐ์ ๋์ผํ ๋ฌธ๋ฒ์ผ๋ก ์ฌ์ฉํ ์ ์๋ค. ๋ํ, ์ด linq.js๋ jQuery ํ๋ฌ๊ทธ์ธ๋ ์ ๊ณตํ๋ฏ๋ก, ๋๋์ฑ ํธ๋ฆฌํ๊ฒ ์ธ ์ ์๋ค.
์ด linq.js๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ์ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ถ๋ฌ๋ค์ฌ์ผ ํ๋ค. ๊ธฐ์์ด๋ฉด jQuery๋ฅผ ํธ์ถํ ํ์ ์ด linq.js๋ฅผ ํธ์ถํ๋๋ก ํ์.
<script src="/path/to/linq.js"></script> <script src="/path/to/linq.jquery.js"></script>
์ด๋ ๊ฒ ํธ์ถํด ๋์ผ๋ฉด ๊ทธ๋ฅ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค. ๋๋ต์ ์ฌ์ฉ ๋ฐฉ๋ฒ์ ์๋์ ๊ฐ๋ค.
var jsonArray = [ { "user": { "id": 100, "screen_name": "d_linq" }, "text": "to objects" }, { "user": { "id": 130, "screen_name": "c_bill" }, "text": "g" }, { "user": { "id": 155, "screen_name": "b_mskk" }, "text": "kabushiki kaisha" }, { "user": { "id": 301, "screen_name": "a_xbox" }, "text": "halo reach" } ]; // ["b_mskk:kabushiki kaisha", "c_bill:g", "d_linq:to objects"] var queryResult = Enumerable.From(jsonArray) .Where(function (x) { return x.user.id < 200 }) .OrderBy(function (x) { return x.user.screen_name }) .Select(function (x) { return x.user.screen_name + ':' + x.text }) .ToArray();
์กฐ๊ธ ๋ ํธํ๊ฒ ๋๋ค ํจ์๋ฅผ ์ด์ฉํ๋ค๋ฉด ์๋์ ๊ฐ์ด ์ฌ์ฉํ ์๋ ์๋ค. ์์ ์๋๋ ๋์ผํ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ ธ์จ๋ค.
// shortcut! string lambda selector var queryResult2 = Enumerable.From(jsonArray) .Where("$.user.id < 200") .OrderBy("$.user.screen_name") .Select("$.user.screen_name + ':' + $.text") .ToArray();
๋ง์ฐฌ๊ฐ์ง๋ก jQuery ํ๋ฌ๊ทธ์ธ์ ์ฌ์ฉํ๋ค๋ฉด ๋์ฑ ๊ฐ๊ฒฐํ ํํ์ ์ธ ์ ์๋ค.
// $.Enumerable: // ์๋ฟ ๋ฉ์์ง๋ก ์ง์๋ง ๋ณด์ฌ์ค๋ค. ์ด ๋ค์ฏ๋ฒ. $.Enumerable.Range(1, 10).Where("$%2==0").ForEach("alert($)"); // TojQuery - Enumerable to jQuery // #select1 ์ด๋ผ๊ณ ํ๋ ID๋ฅผ ๊ฐ์ง ๋๋กญ๋ค์ด๋ฆฌ์คํธ์ ์ต์ ์ 1๋ถํฐ 10๊น์ง ์ถ๊ฐํ๋ค. $.Enumerable.Range(1, 10) .Select(function (i) { return $("<option>").text(i)[0] }) .TojQuery() .appendTo("#select1"); // toEnumerable - jQuery to Enumerable // 1๋ถํฐ 10๊น์ง ์ถ๊ฐํ ๊ฐ์ ๋ชจ๋ ๋ํ๋ค. var sum = $("#select1").children() .toEnumerable() .Select("parseInt($.text())") .Sum(); // 55
์ด๋ ๊ฒ ์ฝ๊ฒ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค. ๋ ๋ง์ ๋ ํผ๋ฐ์ค๋ ์ด๊ณณ์์ ํ์ธํ ์ ์๋ค.
IE6 - 8 ์์ linq.js ์ฌ์ฉํ๊ธฐ โ es5-shim
๋ฌธ์ ๋ ์ญ์๋ IE6, IE7, IE8 ์์ ๋ฐ์ํ๋ค. ๊ทธ ์ด์ ๋ ๊ธฐ๋ณธ์ ์ธ ์๋ฐ์คํฌ๋ฆฝํธ ์ฒ๋ฆฌ ์์ง์ ๋ฒ์ ์ผ๋ก, EcmaScript 5 ๋ฅผ ์ง์ํ์ง ์๋ ๋ธ๋ผ์ฐ์ ์ด๊ธฐ ๋๋ฌธ์ด๋ค. ์ฆ, ๋ฐฐ์ด ์ฒ๋ฆฌ๊ฐ ์๋นํ ์ ํ์ ์ด๋ผ์ ์ด linq.js๊ฐ ์ ๋๋ก ๋์ํ์ง ์๋๋ค.
ํ์ง๋ง, ์ด๋ด ๋ es5-shim ์ด๋ผ๋ ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ์ถ๊ฐํด ์ฃผ๋ฉด IE6-8 ์์๋ ์ด linq.js๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
๋ง์ฝ html5shiv๋ฅผ ์ฌ์ฉํ๋ค๋ฉด, ๋ฐ๋ก ๋ฐ์ ์ด es5-shim ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ถ๊ฐํ๋๋ก ํ์. ์๋๋ผ๋ฉด modernizr ๋ฐ๋ก ๋ฐ์ ์ถ๊ฐํด๋ ๋๋ค.
<script src="/path/to/es5-shim.min.js"></script>
๋จ์ํ ์ด๋ ๊ฒ ์ถ๊ฐํ๋ ๊ฒ ๋ง์ผ๋ก linq.js์ ๊ธฐ๋ฅ๋ค์ ๋ชจ๋ ์ฌ์ฉํ ์ ์๊ฒ ๋๋ค.
์ธํธ๋ผ๋ท์์์ ๊ฐ์ ๋ก IE ๋ฌธ์๋ชจ๋ ์ ํํ๊ธฐ
์ผ๋ฐ์ ์ผ๋ก IE์ ๋ฌธ์๋ชจ๋ Document Mode๋ ๋ธ๋ผ์ฐ์ ์ ๋ฒ์ ์ ๋ง์ถฐ ์๋์ผ๋ก ์ค์ ๋๋ค. IE8์ ์ฌ์ฉ์ค์ด๋ผ๋ฉด ๋ฌธ์๋ชจ๋๋ IE8์ด๊ณ , IE9์ ์ฌ์ฉ์ค์ด๋ผ๋ฉด ๋ฌธ์๋ชจ๋๋ ์๋์ผ๋ก IE9์ด ๋๋ ๊ฒ์ด๋ค.
HTML5 Boilerplate๋ ์ด ๋ฌธ์๋ชจ๋๋ฅผ HTML5์ ๋ง์ถ๊ธฐ ์ํด ๊ฐ๊ธ์ ์ด๋ฉด ์๋ <meta> ํ๊ทธ๋ฅผ <head> ํ๊ทธ ๋ฐ๋ก ๋ฐ์ ์์น์ํค๋ ๊ฒ์ ์ถ์ฒํ๊ณ ์๋ค.
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
๊ทธ๋ฐ๋ฐ, ๋ฌธ์ ๋ ์น์ฌ์ดํธ๊ฐ ์ธํธ๋ผ๋ท ์์ ์กด์ฌํ ๋์๋ IE๋ ๋ฌด์กฐ๊ฑด IE7 ๋ชจ๋๋ก ๋ฐ๊ฟ๋ฒ๋ฆฌ๋ ๊ฒ์ ์๋ค.
์๋ฌด๋ฆฌ ์ ์์ <meta> ํ๊ทธ๋ฅผ ๋ฃ์ด๋ ๋ฌด์กฐ๊ฑด IE7 ๋ชจ๋๋ก ๋ฐ๋๊ธฐ ๋๋ฌธ์ ์ผ๋ฐ์ ์ธ ๋ฐฉ๋ฒ์ผ๋ก๋ ์ธํธ๋ผ๋ท ์์์ IE8 ์ด์์ ๋ฌธ์๋ชจ๋๋ฅผ ๊ตฌํํ ์ ์๋ค.
๋ฐ๋ผ์, HTTP Response Header ๋ถ๋ถ์ ๊ฐ์ ๋ก ์์ ๋ด์ฉ์ ์ฝ์ ํด์ผ ํ๋๋ฐ, ์ด๊ฒ์ ์น์๋ฒ์์ ์ค์ ์ด ๊ฐ๋ฅํ๋ค.
์ ์ด๋ฏธ์ง๋ IIS 6 ์์ ํค๋๋ฅผ ์ค์ ํ๋ ๋ฐฉ๋ฒ์ด๊ณ , ์๋ ์ด๋ฏธ์ง๋ IIS 7 ๋๋ ๊ทธ ์ด์์์ ํค๋๋ฅผ ์ค์ ํ๋ ๋ฐฉ๋ฒ์ด๋ค.
์์ ๊ฐ์ด ์น์๋ฒ์์ ํค๋์ ์ ๋ณด๋ฅผ ์ค์ ํ๊ฒ ๋๋ฉด ์๋์ ๊ฐ์ด ๋ฐ๋๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
์ฐธ๊ณ ๋ก, ์๋ ์ด๋ฏธ์ง๋ IE๊ฐ <meta> ํ๊ทธ์ HTTP Response Header๋ฅผ ํตํด ์ด๋ป๊ฒ ์ ์ ํ ๋ฌธ์๋ชจ๋๋ฅผ ์ค์ ํ๋์ง์ ๋ํ MSDN ๊ณต์ ์ค๋ช ์ด๋ค.
์ฐธ์กฐ:
How Internet Explorer Chooses Between Document Modes
X-UA-Compatibility Meta Tag and HTTP Response Header
Compatibility View
!DOCTYPE Declaration
Configuring IIS to work around webpage display issues in Internet Explorer 8.0

Anya is live and ready to show you everything. Watch her strip, dance, and perform exclusive shows just for you. Interact in real-time and make your fantasies come true.
Free to watch โข No registration required โข HD streaming
Windows Service ์ค์ง์ COM ๊ฐ์ฒด ์ฃฝ์ด๊ธฐ
๋ท๋ท์ผ๋ก Windows Service๋ฅผ ๊ฐ๋ฐํ์ฌ ์์คํ ์ ์ค์นํ ํ ์ ๋ฐ์ดํธ๋ผ๋ ๊ฐ ์ฌํ์ ์ด์ ๋ก Windows Service๋ฅผ ์ธ์ธ์คํจ, ์ค์ง ํน์ ์ฌ์คํํด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค. ์ด ๊ณผ์ ์ด ๋ฑํ ์ด๋ ต๊ฑฐ๋ ํ์ง ์์๋ฐ Windows Service๊ฐ ๋ค๋ฅธ COM ๊ฐ์ฒด๋ฅผ ํธ์ถํ๋ ๊ฒฝ์ฐ์๋ ๋ฌธ์ ๊ฐ ํ๋ ์๋ค.
COM ๊ฐ์ฒด๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ท๋ท ํ๋ ์์ ๋ฐ๊นฅ์์ ๋ง๋ค์ด์ง ๊ฒ๋ค์ด ๋๋ถ๋ถ์ด๋ผ์ ๋ท๋ท ํ๋ ์์์์ ์ฝํธ๋กคํ ์ ์๋ค๊ณ ์๊ฐํ๋ฉด ๋๋๋ฐ, ์ด๋ด ๊ฒฝ์ฐ Windows Service๋ฅผ ์ค์ง์ํค๋ฉด ๋ณดํต์ COM ๊ฐ์ฒด ์ญ์๋ ํ๋ก์ธ์ค๊ฐ ์๋์ผ๋ก ์ฃฝ๊ณ ๋ฉ๋ชจ๋ฆฌ์์ ๋ด๋ ค์ค๊ฒ ๋๋ค. ํ์ง๋ง, ์ฌ์ ํ ๋ฉ๋ชจ๋ฆฌ์์์ ์ข๋นํ๋ก์ธ์ค๋ก ๋จ์์๋ ๊ฒฝ์ฐ๋ ๋ง๋ค. ์ด๋ด ๋ ์ด์ฉ ์ ์์ด ์๋์ผ๋ก ํ๋ก์ธ์ค๋ฅผ ์ฃฝ์ฌ์ผ ํ๋๋ฐ...
์ด๋ด ๊ฒฝ์ฐ ๊ทธ๋๋ง ์ด๋ค ์์ ํ๋ก์ธ์ค๋ฅผ ์๋์ผ๋ก ์ฃฝ์ด๋ ๋ฐฉ๋ฒ์ ์๋น์ค ์ข ๋ฃ ์ด๋ฒคํธ์ ํ๋ก์ธ์ค๋ฅผ ์ฃฝ์ด๋ ๋ก์ง์ ์ถ๊ฐํ๋ ๊ฒ์ด๋ค.
Marshal.ReleaseComObject(instance);
๋ณดํต์ ์ด ๋ช ๋ น์ด ํ์ค๋ก ์ถฉ๋ถํ๋ฐ, ๊ทธ๋๋ ์ฃฝ์ง ์๊ณ ์ด์ ์๋ค๋ฉด ์๋์ ๊ฐ์ ๋ก์ง์ ์ถ๊ฐํ๋ค.
var processName = "MyProcess"; var processes = Process.GetProcessesByName(processName); foreach (var process in processes) { process.Kill(); }
๊ทธ๋ผ ํ์คํ ์ฃฝ์ผ ์ ์๋ค.
IE8 ์์ input ํ๊ทธ์ textarea ํ๊ทธ์ placeholder ์์ฑ ์ ์ฉํ๊ธฐ
IE8์ ๊ณต์์ ์ผ๋ก HTML5 ํ๊ทธ๋ค์ ์ง์ํ์ง ์๋๋ค. ๋ฐ๋ผ์, ํ์ ๋ฒ์ ์ IE๋ค์ ์ํด Modernzr ๋ผ๋ ๊ฐ html5shiv ๊ฐ์ ์๋ฐ์คํฌ๋ฆฝํธ๋ค์ ์ด์ฉํ๋ฉด HTML5์์ ์๋กญ๊ฒ ๋ํ๋ ์๋ฆฌ๋จผํธ ํ๊ทธ๋ค์ ์ฌ์ฉํ ์ ์๋ค.
๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ placeholder ์์ฑ์ IE8์์ ์ฌ์ฉํ ์ ์๋๋ฐ, ์ด๋ด ๋ ์ฌ์ฉํ ์ ์๋ jQuery ํ๋ฌ๊ทธ์ธ์ด ์๋ค. ์ด๋ฆํ์ฌ jquery.placeholder. ์ฌ์ฉ๋ฒ๋ ๊ฐ๋จํ๋ค.
<script src="/path/jquery.placeholder.js"></script>
๋จผ์ jQuery๋ฅผ ๋ก๋ฉํ ๋ค์ jquery.placeholder.js๋ฅผ ๋ก๋ฉํ๋ค. ๊ทธ ๋ค์์ ๋ค์๊ณผ ๊ฐ์ด ์ ์ธํ๋ฉด ๋.
(function ($) { $(document).ready(function () { $("input, textarea").placeholder(); }); })(jQuery);
์ฐธ ์ฝ์ฃ ?
๊ทธ๋ฐ๋ฐ, ์ด๊ฒ ๋ฌธ์ ๊ฐ ํ๋ ์๋ค. Bootstrap ์ด๋ ํจ๊ป ์ฐ๋ฉด <input type="password" ... /> ๊ณผ ๊ฐ์ ํจ์ค์๋ํ input ์๋ฆฌ๋จผํธ๋ ๋ ์ด์์์ด ๊นจ์ ธ ๋ฒ๋ฆฐ๋ค. ๊ทธ๋์, ๋ค ์ข์๋ฐ ์ด๊ฑธ ์ฐ์ง ๋ชปํ๋ ๊ฒ์ด ์ฐธ ์ํ๊น์. ๊ฒฐ๊ตญ ๋ค๋ฅธ ๊ฒ์ ํ๋ ๋ ๋ฐ๊ฒฌํ๋๋ฐ, ์ด๊ฒ์ ์ด๋ฆ์ placeholders.js.
์ด๊ฑด ์ฌ์ฉ๋ฐฉ๋ฒ์ด ๋ ์ฝ๋ค. jQuery ํ๋ฌ๊ทธ์ธ์ด ์๋๊ธฐ ๋๋ฌธ์ ๋ ๋ฆฝ์ ์ผ๋ก ์๋ํ๋๋ฐ ์๋์ ๊ฐ์ด ์คํฌ๋ฆฝํธ๋ง ๋ถ๋ฌ์ค๋ฉด ๋.
<script src="/path/Placeholders.js"></script>
๋ ์ค ํ๋๋ฅผ ์ฌ์ฉํ๋ฉด IE8 ์์๋ placeholder ์์ฑ์ ์ฌ์ฉํ ์ ์๋ค.