이번글에서는 .NetCore , .NET 에서 MSSQL 접속하여 데이터를 가져오고 화면에 표시하는 법을 알아보도록 하겠습니다. 아쉽게도 .Net 프로그래밍에서는 .Net Framework 에서 제공하던 UI(ADO.NET 엔티티 데이터 모델)는 제공하지 않습니다.
C# 에서는 간단히 콘솔 프로그램으로 만들어 콘솔창에 DB 내용을 보여주는 예제를 보여드리도록 하겠습니다.
DB 구조
먼저 MSSQL DB 구조를 보겠습니다. 이번글에서는 DB First 즉 DB 먼저 생성하고 .Net 프로그래밍으로 MSSQL 에 접속해서 데이터를 읽고 쓰는 방법에 대해 알아볼것입니다.
MSSQL 에서 DB 구조가 어떻게 되어 있는지 먼저 보겠습니다. 저는 인터넷에서 많이 사용하는 MSSQL 예제 NorthWind 를 MSSQL 에 생성하였습니다.
위와 같이 Northwind 데이터베이스에서 Orders 라는 테이블의 데이터를 읽어보도록 하겠습니다.
Entity Framework Core를 활용한 기존 데이터베이스 모델링
EF Core와 데이터베이스 모델
EF Core는 이전 버전인 EF 6과 달리 엔터티 및 컨텍스트 클래스를 만드는 데 DB 모델 또는 비주얼 디자이너를 지원하지 않습니다. 이에 따라 명령어를 활용하여 리버스 엔지니어링을 수행해야 합니다. 리버스 엔지니어링 명령어는 기존 데이터베이스의 스키마를 기반으로 엔터티 및 컨텍스트 클래스(파생)를 생성합니다.
Scaffold-DbContext를 활용한 클래스 생성
MS SQL Server의 로컬 데이터베이스에서 SchoolDB 데이터베이스에 대한 엔터티 및 컨텍스트 클래스를 생성해 보겠습니다. Scaffold-DbContext 명령어를 통해 데이터베이스와 연결된 클래스를 자동으로 생성할 수 있습니다.
프로젝트 생성
이제 실전으로 들어갑니다.
비쥬얼 스튜디오를 실행하고 테스트로 C# 콘솔앱을 하나 만들겠습니다. 저는 .Net 7.0 으로 만들겠습니다.
프로젝트 명을 TestMssql로 정해주었습니다.
NuGet에서 다음 패키지를 설치해야 합니다.
Microsoft.EntityFrameworkCore.Design
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Tools
.Net 7.0 기준으로 만들어졌으므로 패키지들도 7.~ 대 버전을 패키지를 설치 하였습니다.
모델생성
Scaffold-DbContext 명령
Scaffold-DbContext
명령어는 기존 데이터베이스를 기반으로 모델을 만드는 데 사용합니다. 패키지 관리자 콘솔에서 Scaffold-DbContext를 사용하여 지정할 수 있는 매개 변수는 다음과 같습니다.
Scaffold-DbContext [-Connection] [-Provider] [-OutputDir]
[-Context] [-Schemas>] [-Tables>]
[-DataAnnotations] [-Force] [-Project]
[-StartupProject] [<CommonParameters>]
위의 규칙을 읽어보시고 제 DB 에서 모델을 생성하도록 하겠습니다. 패키지 관리자 콘솔을 열어줍니다.
다음과 같이 타이핑 합니다.
Scaffold-DbContext “data source=192.168.56.105,1433;Initial Catalog=Northwind;user id=harostudio;password=jjh3164500!;TrustServerCertificate=True;” Microsoft.EntityFrameWorkCore.SqlServer -outputdir Models -context NorthwindContext -contextdir Models -DataAnnotations -Force -Tables Orders,Products
이 명령어는 제 DB 이며 파랗게 칠한 부분을 환경에 맞게 바꿔 주시면 됩니다.
그러면 위와 같이 Models라는 폴더에 모델이 생성된것이 보입니다.
생성된 모델을 한번 볼께요..
NorthwindContext.cs
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
namespace TestMssql.Models;
public partial class NorthwindContext : DbContext
{
public NorthwindContext()
{
}
public NorthwindContext(DbContextOptions<NorthwindContext> options)
: base(options)
{
}
public virtual DbSet<Order> Orders { get; set; }
public virtual DbSet<Product> Products { get; set; }
protected override void OnConfiguring(
DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseSqlServer(
"data source=192.168.56.105,1433;Initial Catalog=Northwind;user"
"id=harostudio;password=jjh3164500!;TrustServerCertificate=True;");
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Order>(entity =>
{
entity.Property(e => e.CustomerId).IsFixedLength();
entity.Property(e => e.Freight).HasDefaultValueSql("((0))");
});
modelBuilder.Entity<Product>(entity =>
{
entity.Property(e => e.ReorderLevel).HasDefaultValueSql("((0))");
entity.Property(e => e.UnitPrice).HasDefaultValueSql("((0))");
entity.Property(e => e.UnitsInStock).HasDefaultValueSql("((0))");
entity.Property(e => e.UnitsOnOrder).HasDefaultValueSql("((0))");
});
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
Orders.cs
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
namespace TestMssql.Models;
[Index("CustomerId", Name = "CustomerID")]
[Index("CustomerId", Name = "CustomersOrders")]
[Index("EmployeeId", Name = "EmployeeID")]
[Index("EmployeeId", Name = "EmployeesOrders")]
[Index("OrderDate", Name = "OrderDate")]
[Index("ShipPostalCode", Name = "ShipPostalCode")]
[Index("ShippedDate", Name = "ShippedDate")]
[Index("ShipVia", Name = "ShippersOrders")]
public partial class Order
{
[Key]
[Column("OrderID")]
public int OrderId { get; set; }
[Column("CustomerID")]
[StringLength(5)]
public string? CustomerId { get; set; }
[Column("EmployeeID")]
public int? EmployeeId { get; set; }
[Column(TypeName = "datetime")]
public DateTime? OrderDate { get; set; }
[Column(TypeName = "datetime")]
public DateTime? RequiredDate { get; set; }
[Column(TypeName = "datetime")]
public DateTime? ShippedDate { get; set; }
public int? ShipVia { get; set; }
[Column(TypeName = "money")]
public decimal? Freight { get; set; }
[StringLength(40)]
public string? ShipName { get; set; }
[StringLength(60)]
public string? ShipAddress { get; set; }
[StringLength(15)]
public string? ShipCity { get; set; }
[StringLength(15)]
public string? ShipRegion { get; set; }
[StringLength(10)]
public string? ShipPostalCode { get; set; }
[StringLength(15)]
public string? ShipCountry { get; set; }
}
위와 같이 접속 정보와 모델이 자동을 구성 되었습니다.
데이터 가져오기
Program.cs 에서 다음처럼 코딩후 실행 시켜 보겠습니다.
Orders Table 에서 데이터를 한개 쓰고 모든 데이터를 표시해보겠습니다.
using Microsoft.EntityFrameworkCore.Storage;
using TestMssql.Models;
namespace TestMssql
{
internal class Program
{
static void Main(string[] args)
{
using (var context = new NorthwindContext())
{
var transaction = context.Database.BeginTransaction();
context.Orders.Add(new Order { CustomerId= "WOLZA" });
context.SaveChanges();
transaction.Commit();
foreach (var row in context.Orders)
{
Console.WriteLine(
$"OrderId : {row.OrderId} - CustomerId : {row.CustomerId}");
}
Console.WriteLine(
$"총 {context.Orders.Count()} 개 가 출력되었습니다." );
}
}
}
}
실행 시키면 다음과 같이 실행 됩니다.
var transaction = context.Database.BeginTransaction();
context.Orders.Add(new Order { CustomerId= "WOLZA" });
context.SaveChanges();
transaction.Commit();
위에서처럼 Order테이블에 CustomID(“WOLZA”) 를 하나 입력하고 모든 ID 를 표시하는 프로그램을 만들어보았습니다. WOLZA 가 Insert되었고 표시되는 것을 볼 수 있습니다.
만약 .Net Core, .Net 이 아닌 .Net Framework 에서 MS SQL 접속할 경우 다음글을 참조 하시면 됩니다.
결론
.Net 에서 EntityFramework으로 MSSQL DB를 아주 쉽게 컨트롤 하는 방법을 배웠습니다.
DB 연결은 이렇게 쉽게 구성하였으니 EntityFrameWork 을 사용하여 Web 서버 또는 WPF 같은 UI 프로그램에서도 쉽게 접근하고 개발할 수 있습니다.