- ๋ณ์์์ ์ ๊ณตํ๋ ์ ์ ๋ฌธ์งํ ์์ฑ ๋ฐ ๊ด๋ฆฌ ๊ธฐ๋ฅ ์ค ์ผ๋ถ๋ฅผ C# .NET Framework ๋ฐ EntityFramework๋ฅผ ์ด์ฉํด ๊ตฌํํ์๋ค.
- 2020๋ 11์ 23์ผ ~ 2020๋ 11์ 29์ผ
- IoT๊ธฐ๋ฐ ์ค๋งํธํฉํ ๋ฆฌ SW๊ฐ๋ฐ ์ ๋ฌธ๊ฐ๊ณผ์
- ๊น๋๊ทผ, ์์ฑ์ค, ์ด๋ํฌ ์ด 3๋ช
- ๋ฌธ์งํ๋ฅผ ์์ฑํ ๊ณ ๊ฐ์ ์ ๋ณด๋ฅผ ํ์ธํ ์ ์๋ค. ๋ํ, ๊ณ ๊ฐ ์ ๋ณด์ ์์ ๋ฐ ์ญ์ ๊ฐ ๊ฐ๋ฅํ๋ค.
- ๊ณ ๊ฐ ์ ๋ณด๋ฅผ ์ญ์ ํ๊ฒ ๋๋ฉด ๊ณ ๊ฐ์ด ์์ฑํ๋ ๋ฌธ์งํ์ ์ ๋ณด๋ ๊ฐ์ด ์ญ์ ๋๋ค.
- ์ง์๋ค์ ์ ๋ณด๋ฅผ ํ์ธํ ์ ์๋ค. ๊ฐ์ธ ์ ๋ณด๋ฅผ ํฌํจํ ์ง๊ธ ์ ๋ณด์ ์ง๋ฃ๊ณผ ์ ๋ณด๋ฅผ ํ์ธํ ์ ์๋ค.
- ์ง์์ ์ถ๊ฐ ๋ฐ ์์ , ์ญ์ ๊ฐ ๊ฐ๋ฅํ๋ค.
- ์์ฑ๋ ๋ฌธ์งํ์ ์ ๋ณด๋ฅผ ํ์ธํ ์ ์๋ค. ๋ฌธ์งํ์ ์ ๋ณด๋ ์ง๋ฃ๊ณผ, ์์ฑ ์ผ์ ๋ฐ ์์ฑํ ๊ณ ๊ฐ์ ์ ๋ณด๋ก ์ด๋ฃจ์ด์ ธ ์๋ค.
- ๋ฌธ์งํ์ ์ด๋ ๋ฐ ์ญ์ ๊ฐ ๊ฐ๋ฅํ๋ฉฐ, ์์ฌ์ ๋ณ์์ฅ์ ๊ฒฝ์ฐ์๋ ์ง๋จ ๋ด์ฉ ์์ฑ์ด ๊ฐ๋ฅํ๋ค.
- ๋ฌธ์งํ ์ง๋ฌธ ์ ๋ณด๋ฅผ ์ง๋ฃ๊ณผ๋ณ๋ก ํ์ธํ ์ ์๋ค.
- ๋ฌธ์งํ์ ์ง๋ฌธ ์ถ๊ฐ, ์์ , ์ญ์ ๊ฐ ๊ฐ๋ฅํ๋ค.
- ์ด๋ฆ๊ณผ ์๋ ์์ผ ์ ๋ณด๋ ์์ ๋์ง ์๋๋ก ํ๋ค.
- ๋ฌธ์งํ ์์ฑ ์ด๋ ฅ์ด ์๋ ํ์์ ๊ฒฝ์ฐ, ์ ๋ณด๊ฐ ๋ฏธ๋ฆฌ ์ถ๋ ฅ๋๋ค.
- ์ง๋ฌธ ์ข ๋ฅ(์ฃผ๊ด์, ๊ฐ๊ด์, ๋ค์ค์ ํ)์ ๋ฐ๋ผ ๋ค๋ฅธ ์์์ผ๋ก ์ถ๋ ฅ๋๋ค.
- ๋ฌธ์งํ๋ฅผ ๋ค ์์ฑํ ์ดํ์
์ ๋ ฅ์๋ฃ
๋ฒํผ์ ๋๋ฅด๋ฉด ์์ฑํ ๋ฌธ์งํ์ ํ์ ์ ๋ณด๊ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ๋๊ณ ,1. ๊ธฐ๋ณธ ์ ๋ณด ์ ๋ ฅ
ํ๋ฉด์ผ๋ก ๋์๊ฐ๊ฒ ๋๋ค.
- ์ง๊ธ ๋ณ๋ก ์ ํํ ์ ์๋ ์์ ์ ๋ฒํผ์ ๋นํ์ฑํ ๋๋ค.(์ง์ํ์)
- ์ ํ๋ ๋ฌธ์งํ์ ์ด๋ ๋ฐ ์ง๋จ์ ์์ฑ, ์ญ์ ๊ฐ ๊ฐ๋ฅํ๋ค
- ๋ฌธ์งํ ์ง๋ฌธ์ ์ถ๊ฐ, ์์ , ์ญ์ ๊ฐ ๊ฐ๋ฅํ๋ค
- ์ง๋ฌธ์ ์ ํ์ ์ฃผ๊ด์, ๊ฐ๊ด์, ๋ค์ค์ ํ์ด๋ค
- ์์ ํ
์ผ๊ด์ ์ฅ
๋ฒํผ์ ๋๋ฌ์ผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ๋๋ค
- ์ ํ๋ ํ์์ ์ ๋ณด ์์ ๋ฐ ์ญ์ ๊ฐ ๊ฐ๋ฅํ๋ค
- ์ง์์ ์ถ๊ฐ๊ฐ ๊ฐ๋ฅํ๋ค. ์ง์ ์ถ๊ฐ ์ ๋น๋ฐ๋ฒํธ๋ ์ด๊ธฐ๊ฐ(password)์ผ๋ก ์๋ ์ ์ฅ๋๋ค
- ์ ํ๋ ์ง์์ ์์ ๋ฐ ์ญ์ ๊ฐ ๊ฐ๋ฅํ๋ค
- C# 8.0
- .Net FrameWork 4.8
- EntityFrameWork 6.2
- Winform
- MSSQL Server 2019
- Windows 10
- Microsoft Visual Studio Community 2019 v16.8
- Microsoft SQL Server Management Studio v18.6
- ๋ชจ๋ ํญ๋ชฉ์ด ์ 3 ์ ๊ทํ๊น์ง ์๋ฃ๋๋ค
DB ํ ์ด๋ธ์ ์์ฑ ๋ณ๊ฒฝ ๋ฑ ์ ๋ฐ์ดํธ ๋ด์ญ์ด EntityFramework์ ๋ฐ์๋์ง ์์ ๋ฌธ์ #24
- ๋ฌธ์งํ ์ ์ฅ์ ๋๋ฅผ ์ ์๋ฌ ๋ฐ์
- EntityFramework๋ก ๋ถ๋ฌ์จ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฌธ์งํ ํ ์ด๋ธ PK์ปฌ๋ผ์ IDENTITY_INSERT ์์ฑ์ด OFF๋ก ๋์ด์์๋ค
- ์ฒ์์๋ DB์ ์๋ ๋ฌธ์งํ ํ ์ด๋ธ PK์ปฌ๋ผ์ IDENTITY_INSERT ์์ฑ์ ON์ผ๋ก ๋ณ๊ฒฝํ๋ค. ํ์ง๋ง ๊ฐ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค.
- ํ์ธ ๊ฒฐ๊ณผ, ์ฒ์์ DB ์คํค๋ง ์ค๊ณ ์ ํ ์ด๋ธ PK์ IDENTITY_INSERT ์์ฑ์ ON์ผ๋ก ๋ฐ๊พธ์ง ์์๊ณ , ๊ทธ ์ํ๋ก EntityFramework๋ก ๋ถ๋ฌ์, EntityFramework์์๋ IDENTITY_INSERT ์์ฑ์ด OFF๋ก ์ ์ฅ๋์ด ์์๋ค.
- ๊ทธ๋์, EntityFramework ๋ค์ด์ด๊ทธ๋จ์์ ์ฐํด๋ฆญ์ผ๋ก ์ ๊ณตํ๋ '๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๋ชจ๋ธ ์ ๋ฐ์ดํธ'๋ฉ๋ด๋ฅผ ์คํ, ์ ๋ฐ์ดํธ ๋ง๋ฒ์ฌ๋ฅผ ์ด์ฉํด DB์ ์ ๋ณด๋ฅผ ์ ๋ฐ์ดํธํ์ฌ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํจ
์ธ๋ํค๋ก ์ฐ๊ฒฐ๋ ์ฌ๋ฌ ํ ์ด๋ธ์ ๊ฐ์ ๋์์ ์ฝ์ ํ๋ ํธ๋์ญ์ ์งํ์ค์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ ๋ฌธ์ #24
- ์๋ก์ด Customer(ํ์)๊ฐ ๋ฌธ์งํ๋ฅผ ์ ๋ ฅํ๋ฉด, ์๋ฌ๊ฐ ๋ฐ์
- ์ ๊ท ํ์๊ฐ ๋ฌธ์งํ ์ ๋ ฅ์ด ์๋ฃ๋๋ฉด Customer(๊ณ ๊ฐ), Questionnare(๋ฌธ์งํ), Response(๋ฌธ์งํ์๋ต) ์ด 3๊ฐ์ ํ ์ด๋ธ์ ๋ฐ์ดํฐ๊ฐ ์ฝ์ ๋๋๋ฐ, ์ด ๋ ์ ๊ท ํ์๋ ๋ฑ๋ก ์ ์๋ CustomerID๊ฐ ์์ด, Customerํ ์ด๋ธ์์ ํค๊ฐ์ ์ต๋๊ฐ์ ๊ฐ์ ธ์ ๋ฑ๋กํ๋๋ฐ ์ด ๊ฐ์ด ์ค์ IDENTITY ์ปฌ๋ผ์ ํตํด ์ ์ฅ๋๋ ๋ด์ฉ๊ณผ ๋ง์ง ์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค
- ์ฌ๋ฌ ํ ์ด๋ธ์ ๋ฐ์ดํฐ๊ฐ ๋์์ ์ ์ฅ๋๋ ํธ๋์ญ์ ์ ๋์ง ์๊ณ IDENTITY ์ปฌ๋ผ์ ๊ฐ์ ๋ฏธ๋ฆฌ ๊ตฌํด์ ์ ์ฅํ๊ฑฐ๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ด ํ์ํ๋ค.
- ์ฒ์์๋ C#์์ IDENTITY ์ปฌ๋ผ์ ๊ฐ์ ๊ตฌํ๋ ๋ฒ์ ์ฐพ๊ณ ์์๋๋ฐ, ๊ฒ์ ํ๋ ๋์ค ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ๋ฐ๊ฒฌํ๋ค
- EF๊ฐ ID๊ฐ์ ์ฐพ์ ํ ๋นํ๋ ๊ฒ์ด ์๋๋ผ ํ ์ด๋ธ ๊ฐ์ฒด ์์ฒด๋ฅผ ํ ๋นํ๋ ๊ธฐ๋ฅ์ ์ง์ํ๋ฉฐ, EF๋ก ์์ฑ๋ Entity ๋ชจ๋ธ์ ์์ฑ๋์ด ์๋ ์ธ๋ํค๋ก ์ฐ๊ฒฐ๋ ํ์ ๋ชจ๋ธ์ ์ด์ฉํด ์ฐ๊ฒฐํ ์ ์๋ค๋ ๊ฒ์ ์๊ฒ ๋์๋ค.
- ๊ทธ๋์ Entity ๋ชจ๋ธ์ ๊ฐ์ฒด๋ฅผ ์์ฑํ ๋ ์์ ํ ์ด๋ธ ๊ฐ์ฒด๋ฅผ ์ฐ๊ฒฐํด์ฃผ๋ฉด, ํ๋ฒ์ SaveChange๋ฅผ ์งํํด๋ Insert๋ ๊ฐ์ฒด์ ๋ํด ์๋์ผ๋ก IDํค๊ฐ ์ฐ๊ฒฐ๋์ด ์๋ฌ๊ฐ ๋ฐ์ํ์ง ์๊ณ ํธ๋์ ์ ๋ ๊นจ์ง์ง ์๊ฒ ๋๋ค.
- ๊ทธ๋์ ๊ฐ์ฒด๋ฅผ ์์ฑํ ๋, ์์ ํ ์ด๋ธ ๊ฐ์ฒด๋ฅผ ์ฐ๊ฒฐํด์ฃผ๋ ์์ ์ ์งํํ๋ค.
public Questionnare CreateQuestionnare { get; set; }
// before
CreateQuestionnare = new Questionnare();
// after
CreatedQuestionnare = new Questionnare { Customer = ConnectedCustomer };
ํฌ์ปค์ค ๋ณํ์ ๋ฐ๋ผ ๊ฐ์ ๋ก ์คํฌ๋กค์ด ์กฐ์ ๋๋ ๋ฌธ์ #26
- "์ ๋ ฅ์๋ฃ"๋ฒํผ์ ๋๋ฅด๋ฉด ํจ๋ ์ปจํธ๋กค์ ์คํฌ๋กค์ด ๋งจ ์๋ก ์ฌ๋ผ๊ฐ๋ ํ์
- ํ์ธ ๊ฒฐ๊ณผ, ํ ์คํฌ๋กค์ด๋ ๋ค๋ฅธ ํ๋์ ํ ์ดํ ํจ๋ ์ปจํธ๋กค ๋ด์ ์๋ ๋ค๋ฅธ ์ปจํธ๋กค์ ํด๋ฆญํ์ฌ Focus๊ฐ ๋๋ฉด, ํจ๋ ์ปจํธ๋กค์ด ActiveControl๋ก ๊ฐ์ฃผ๊ฐ ๋์ด ์ด๋ค ๊ฒฝ๋ก๋ฅผ ํตํดScrollableControl.ScrollToControl ๋ฉ์๋๊ฐ ์คํ๋๊ณ ์คํฌ๋กค ์์น๊ฐ ๊ฐ์ ๋ก ์ฎ๊ฒจ์ง๋ ๊ฒ์ผ๋ก ํ๋จ๋๋ค.
- ScrollToControl์ด ๊ฐ์ ๋ฉ์๋์ด๊ธฐ ๋๋ฌธ์, ํจ๋ ์ปจํธ๋กค์ ์์๋ฐ๋ CustomPanelํด๋์ค๋ฅผ ๋ง๋ค๊ณ ScrollToControl ๋ฉ์๋๋ฅผ ์ค๋ฒ๋ผ์ด๋ํ์ฌ ์ฐ๋ฆฌ๊ฐ ์ํ๋ ๋์์ ํ๋๋ก ์์ ํ์ฌ ํด๊ฒฐ
- ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธด ํ์ง๋ง, ์ ํํ๊ฒ ScrollToControl์ด ์ด๋ค ์๋ฆฌ๋ก ๋์ํ๋์ง์ ํจ๋๊ณผ ์คํฌ๋กค์ ์๊ด๊ด๊ณ๋ฅผ ์ ํํ๊ธฐ ์ดํดํ์ง๋ ๋ชปํจ
public class CustomPanel : System.Windows.Forms.Panel
{
protected override System.Drawing.Point ScrollToControl(System.Windows.Forms.Control activeControl)
{
// Returning the current location prevents the panel from
// scrolling to the active control when the panel loses and regains focus
return this.DisplayRectangle.Location;
}
}
- ์ถ์ฒ https://blog.naver.com/raon_pgm/150185087803 https://nickstips.wordpress.com/2010/03/03/c-panel-resets-scroll-position-after-focus-is-lost-and-regained/
ํด๋์ค ๋จ์๋ก ๋ฐ์ดํฐ ๊ด๋ฆฌ ์ค ์์ ๋ณต์ฌ๋ก ์ธํด ๋ฐ์ดํฐ์ ์์ค์ด ์ผ์ด๋ ๋ฌธ์ #61
- ๋ฌธ์งํ ๋ฌธ์ ๊ด๋ฆฌ์์ ๋ฌธ์ ๋ฅผ ์ค๊ฐ์ ์ถ๊ฐํ๊ฑฐ๋, ๋ฌธ์ ์ ์์น๋ฅผ ์์ ํ๋ ๋ฑ์ ์์น ๋ณ๊ฒฝ ์์ ์ด ์งํ๋ ๋, ๋ณ๊ฒฝ๋ ๋ฌธ์ ๋ก ์ธํด ํจ๊ป ๋ณ๊ฒฝ๋๋ ๋ค๋ฅธ ๋ฌธ์ ๋ค์ ์ธ๋ฑ์ค๊ฐ ๋น์ ์์ ์ผ๋ก ๋ณํ๋ ๋ฌธ์
- ๋ฌธ์งํ ๋ฌธ์ ๊ด๋ฆฌ๋ฅผ ๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋ ๋ ๋ง๋ค ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ก ์ง์ ์ฐ๊ฒฐํด ๋ณ๊ฒฝํ๋ ๊ฒ์ด ์๋๋ผ, ํ๋ก๊ทธ๋จ ๋ด ๊ฐ์ฒด๋ก ๊ด๋ฆฌ๋ฅผ ํ๋ค๋ณด๋ ์์ฐ์ค๋ฝ๊ฒ ํด๋์ค(Entity)๋จ์๋ก ๊ด๋ฆฌ๋ฅผ ํ๊ฒ ๋๋๋ฐ, ํด๋์ค๊ฐ ์ฐธ์กฐ ํ์ ์ด๊ธฐ ๋๋ฌธ์ ๋ฐ์ดํฐ๋ฅผ ๋ณต์ฌํ์ฌ ์ถ๊ฐํ๋ ๊ณผ์ ์์ '์์ ๋ณต์ฌ'๊ฐ ๋ฐ์ํด ๋ฐ์ดํฐ ๋ณ๊ฒฝ ๋ก์ง์ด ๊ผฌ์๋ค.
- ๋ฐ์ดํฐ๋ฅผ ๋ณต์ฌํด ์์ ํ๋ ๋ถ๋ถ ์ค ๊ฐ์ฒด๊ฐ '๋ณต์ฌ'๋๋ ๋ถ๋ถ์์ '๊น์ ๋ณต์ฌ'๊ธฐ๋ฅ์ ๊ตฌํํ์ฌ ์ ์ฉํ์ฌ ํด๊ฒฐํ๋ค
- ๊น์ ๋ณต์ฌ ๊ธฐ๋ฅ์ EF๋ก ์์ฑ๋ Entity ํด๋์ค๋ฅผ Patialํด๋์ค๋ก ๋ค๋ฅธ๊ณณ์์ ์์ ํ์ฌ ๊น์ ๋ณต์ฌ ๊ธฐ๋ฅ(๋ฉ์๋)์ ๋ง๋ค์ด ํด๊ฒฐํ๋ค.
- ๊น์ ๋ณต์ฌ ๊ธฐ๋ฅ์ ํ๋ Clone๋ฉ์๋๋ฅผ ๋ง๋ค๋๋ C#์์ ์ ๊ณตํ๋ ICloneable ์ธํฐํ์ด์ค๋ฅผ ์์ํ์ฌ ์์ ํ๋ค.
public partial class Question : ICloneable
{
public object Clone()
{
Question question = new Question();
// ...
return question;
}
}
// before
Question question = AfterQuestions.FindAll(x => x.Index == i)
.OrderByDescending(x => x.Version)
.FirstOrDefault();
question.Index++;
// after
var data = AfterQuestions.FindAll(x => x.Index == i)
.OrderByDescending(x => x.Version)
.FirstOrDefault();
Question question = (Question)data.Clone();
question.Index++;
๊ฐํ์ ์ผ๋ก ์ ์์ค์ธ ์ง์์ ์ ๋ณด๊ฐ ์ฌ๋ผ์ง๋ ๋ฌธ์ #74
- ์ ์ํ์ฌ ์์ ํ ๋ค๋ฅธ id๋ก ๋ก๊ทธ์ธ ์ ๊ฐํ์ ์ผ๋ก ์ค๋ฅ ๋ฐ์
- ์ง๋จ ๋ด์ฉ ์์ฑ ํผ์ ์ ๋ฌ๋ ์ ์์ค์ธ ์ง์์ ID๊ฐ์ด null๋ก ๋จ
- ์์ธ์ ์ฐพ๋ ์ค, ๋ฌธ์งํ ๊ด๋ฆฌ ๋ค๋ก๊ฐ๊ธฐ ๋ฒํผ ์ด๋ฒคํธ ํ์ฑ ์ ์ ์์ค์ธ ์ง์์ ์ ๋ณด๊ฐ ์ ๋ฌ์ด ๋์ง ์๋ ๋ฌธ์ ๋ฅผ ๋ฐ๊ฒฌ
- ๋ฌธ์งํ ๊ด๋ฆฌ ๋ค๋ก๊ฐ๊ธฐ ๋ฒํผ ์ด๋ฒคํธ ํ์ฑ ์, ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ํตํด ์ ์์ค์ธ ์ง์์ ์ ๋ณด๊ฐ ์ ๋ฌ๋๋๋ก ๋ณ๊ฒฝํจ. ๋ํ, ๋ฌธ์งํ ์ง๋ฌธ ๊ด๋ฆฌ, ์ง์ ๊ด๋ฆฌ, ๊ณ ๊ฐ ๊ด๋ฆฌ์ ๊ฐ ๋ฒํผ ์ด๋ฒคํธ ํธ๋ค๋ฌ ๊ตฌ๋ฌธ์ ์ ์์ค์ธ ์ง์์ ์ ๋ณด๊ฐ ์ ๋ฌ๋๋๋ก ์์
- ๋ฌธ์ ์ ๋ฐ์ ๋น๋์ ์กฐ๊ฑด์ด ์ ํํ๊ฒ ๊ท๋ช ๋์ง ์์ ๋ฌธ์ ์ด๋ฏ๋ก, ์ ์ฉ๋ ์๋ฃจ์ ์ ํตํด ํด๋น ๋ฌธ์ ๊ฐ ์์ ํ ํด๊ฒฐ๋์๋ค๊ณ ๋จ์ธํ ์ ์์. ์ถ๊ฐ ํ ์คํธ๋ฅผ ํตํด ํด๋น ์ค๋ฅ ๋ฐ๊ฒฌ์ ์กฐ์น ํ์
// before
private void btnGoBack_Click(object sender, EventArgs e)
{
EmployeeSelectFunctionControl employeeSelectFunctionControl =
new EmployeeSelectFunctionControl();
OnbtnCancelClicked(employeeSelectFunctionControl);
}
// after
private void btnGoBack_Click(object sender, EventArgs e)
{
EmployeeSelectFunctionControl employeeSelectFunctionControl =
new EmployeeSelectFunctionControl(currentEmployeeInHere);
OnbtnCancelClicked(employeeSelectFunctionControl);
}