일반적으로 client - api - DB 로 설계되는 three tier 시스템에서는,
db 에 대한 접근은 오로지 api 에게만 허용되고, DB는 외부로 노출되지 않습니다.
api 가 DB 에 접근할 때는 생쿼리 또는 DbContext 중 하나를 선택할 수 있습니다.
클라이언트(프론트 엔드, 데스크탑 앱, 모바일 앱)는 api 를 통해서만 데이터를 얻을 수 있기에, Http 만 있지, 생쿼리도, DbContext도 개입할 여지가 없습니다.
클라이언트와 api 는 Http 를 통해 json 데이터를 주고 받는데, serialization 을 통해 인스턴스를 생성합니다. 이때, json 과 맵핑되는 데이터 모델이 별도로 필요하게 됩니다.
namespace MyProject.Core.Entities;
public class MyDataEntity
{
// ...
[ForeignKey(“user_id”)] public User? user {get; set;}
// ...
}
namespace MyProject.Api.Contracts;
public class MyDataInsertion
{
// ...
public Guid UserId { get; set; }
// ...
}
// WPF 앱
using MyProject.Api.Contracts;
namespace MyProject.Client.Windows.Services;
class MyDataService
{
private HttpClient _httpClinet;
// ...
public async Task Add(MyDataInsertion data)
{
// data 를 json 객체로 serializaiton 한 다음,
// 요청의 바디 또는 form data 로 api 에 Post 합니다.
}
}
// Wep Api Program.cs
using MyProject.Api.Contracts;
using MyProject.Core.Entities;
namespace MyProject.Api;
// ...
app.MapPost("/api/mydata",
async ([FromBody] MyDataInsertion data, [FromServices] AppDbContext context) =>
{
var user = await context.Users
.FirstOrDefaultAsync(x => x.User.Id == data.UserId);
if (user is null) return Results.BadRequest();
// MyData => MyDataEntity 로 맵핑
var entity = new MyDataEntity
{
User = user,
// ...
};
context.MyDataEntities.Add(entity);
context.SaveChanges();
reutrn Results.Ok();
});
// ...
Api.Contracts 에 속한 데이터 모델들은 API가 외부(인터넷으)로 천명하는 계약이라, 신중하게 설계해야 합니다. 런칭 후 변경할 일이 있다면, 모델을 수정하는 것보다, Api.V2.Contracts 와 같이 별도의 네임스페이스에 새로 추가하는 것이 좋습니다.
객체간 매핑은 별도의 맵퍼를 통해 처리하는 것이 코드 관리 측면에서 유리합니다.