안녕하세요.
지나간 혹은 지워지고 있는 분야인 LinqToSql을 만지작하면서 있는데 질의하는 방법을 모르겠네요..
아래의 질문자 링크와 거의 같다고 보면됩니다.
Entity Framework에서는 Include가 있는 것 같은데요..
다시 돌아와서 제가 원하는 것은 아래와 같습니다.
쿼리로 표현하면
select
us.UserName,
dp.DeptName
from
[User] us
inner join DeptUser du on us.id = du.userId
inner join Dept dp on du.deptId = dp.id
where
us.userId ='jang'
and du.active = 1
링큐로 표현한다면(물론 제가 원하는 바는 아닙니다. usdp를 join만 했고 select하지 않았기 때문)
from us in Users
where us.UserId == "jang"
join usdp in DeptUsers on us.Id equals usdp.UserId
where usdp.Active == true
select us
대충 결과는 아래와 같습니다.
말로써 표현하면
“jang이라는 아이디를 사용하는 사용자의 현재 부서의 정보를 구하라” 입니다.
다만 LINQ Class가 모두 ER 같이 ORM 모델로 이루어져 User기준으로 구하고 싶네요.
new를 사용하여 익명객채 사용하지 않구요.
ORM을 온전히 사용해보고 싶네요.
특정 USER를 선택하고 DEPTUSER 속성에서 현재 부서를 선택하고, 선택된 DEPTUSER에서 DEPT를 속성으로 쭉 타고 구하면 좋을 것 같네요…
그러면 USER 객체를 구할 수 있고 관련된 정보는 모두 구조적으로 데이터를 가질 수 있으니까요. 알려진 타입이라 함수를 지역을 벗어날 수도 있고요.
분명 방법이 있을 것 같은데 거의 new를 해서 사용하다보니 원래 그려러고 했는지 모르겠지만 ORM 기능을 온전히 사용 해 보고 싶네요.
User와 Dept로 엔터티를 만든 후, 질문자님이 만드신 구조를 참조해서 다 대 다 탐색 속성을 부여했습니다.
| User
[Table(nameof(User))]
public record User
{
[Key]
public string UserId { get; set; } = default!;
public string UserName { get; set; } = default!;
public virtual ICollection<Dept> Depts { get; set; } = default!;
}
| Dept
public record Dept
{
[Key]
public string DeptId { get; set; } = default!;
public string DeptName { get; set; } = default!;
public virtual ICollection<User> Users { get; set; } = default!;
}
여기서 User의 Depts 속성과 Dept의 Users의 속성이 탐색 속성 입니다.
| Context
public class Context : DbContext
{
public DbSet<User> Users => Set<User>();
public DbSet<Dept> Depts => Set<Dept>();
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// "database.db" 파일로 SQLite 사용
optionsBuilder.UseSqlite("Data Source=database.db")
.UseLazyLoadingProxies();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
}
SQLite로 간단한 DBContext를 만들고요, 중요한 건 .UseLazyLoadingProxies()로 지연 로딩을 활성화 해야 합니다.
데이터베이스 업데이트를 하면 다음의 테이블이 생성됩니다.
삽입
// 사용자 및 부서 삽입 {{{
var newUser = new User
{
UserId = "test",
UserName = "테스트",
Depts = new List<Dept> { new() { DeptId = "test_grp", DeptName = "테스트 부서" } }
};
c.Users.Add(newUser);
c.SaveChanges();
이렇게 하면 데이터베이스의 테이블에 다음과 같이 값이 삽입 됩니다.
이제 탐색 속성과 지연 로딩에 의해 다음처럼 질의가 가능하게 됩니다.
var user = c.Users.Find("test"); // test 사용자를 찾아
if (user is null)
return;
// 사용자명과 사용자의 부서명 출력
Console.WriteLine($"User : {user.UserName}({user.UserId})");
Console.WriteLine($"User Dept : {user.Depts.First().DeptName}");
늦었지만 답변 감사합니다. 소스도 올려주셔서 감사합니다.
다만 결과물은 같을 수 있겠으나 과정이 조금 다른 것 아닌가 합니다.
저의 의도는 아래와 같이 lazy로딩과 관련 없이 relationship 있는 속성을 비즈니스 코드를 적용하여 확증적 으로 조회하여 바로 사용 하는 것입니다.
또한 조회한 후 바로 직렬화 하는 경우입니다.
앞서 언급한 바와 같이 Include,ThenInclude가 저의 의도에는 더 맞는 것 갔습니다.
var use2 = c.Users.Include(u=> u.Depts.Where(d=>d.Active== true));