[C#] 익명 유형 결과를 반환 하시겠습니까?

아래의 간단한 예제를 사용하면 Linq를 사용하여 여러 테이블에서 결과를 SQL로 반환하는 가장 좋은 방법은 무엇입니까?

두 개의 테이블이 있다고 가정 해보십시오.

Dogs:   Name, Age, BreedId
Breeds: BreedId, BreedName

와 함께 모든 개를 반환하고 싶습니다 BreedName. 나는 모든 개에게 아무런 문제없이 이와 같은 것을 사용해야합니다.

public IQueryable<Dog> GetDogs()
{
    var db = new DogDataContext(ConnectString);
    var result = from d in db.Dogs
                 join b in db.Breeds on d.BreedId equals b.BreedId
                 select d;
    return result;
}

그러나 품종이있는 개를 원하고 이것을 시도하면 문제가 있습니다.

public IQueryable<Dog> GetDogsWithBreedNames()
{
    var db = new DogDataContext(ConnectString);
    var result = from d in db.Dogs
                 join b in db.Breeds on d.BreedId equals b.BreedId
                 select new
                        {
                            Name = d.Name,
                            BreedName = b.BreedName
                        };
    return result;
}

이제 컴파일러가 Dogs를 기대하기 때문에 익명의 유형 집합을 반환 할 수는 없지만 사용자 정의 유형을 만들지 않고도 이것을 반환 할 수있는 방법이 있습니까? 아니면 자신의 클래스를 만들고 DogsWithBreedNamesselect에서 해당 유형을 지정해야합니까? 아니면 다른 쉬운 방법이 있습니까?



답변

나는이 패턴을 찾는 경향이있다 :

public class DogWithBreed
{
    public Dog Dog { get; set; }
    public string BreedName  { get; set; }
}

public IQueryable<DogWithBreed> GetDogsWithBreedNames()
{
    var db = new DogDataContext(ConnectString);
    var result = from d in db.Dogs
                 join b in db.Breeds on d.BreedId equals b.BreedId
                 select new DogWithBreed()
                        {
                            Dog = d,
                            BreedName = b.BreedName
                        };
    return result;
}

그것은 당신이 여분의 클래스를 가지고 있음을 의미하지만, 빠르고 쉽고 코딩이 쉽고, 쉽게 확장 가능하고 재사용 가능하며 유형 안전합니다.


답변

익명 유형을 반환 있지만 실제로는 그렇지 않습니다 .

이 경우 적절한 유형을 만드는 것이 훨씬 낫습니다. 메서드가 포함 된 형식 내에서만 사용하려는 경우 중첩 형식으로 만듭니다.

개인적으로 C #에서 “명명 된 익명 형식”을 가져 오길 원합니다. 즉 익명 형식과 같은 동작이지만 이름과 속성 선언이 있지만 그게 전부입니다.

편집 : 다른 사람들은 개를 반환 제안 한 다음 속성 경로 등을 통해 품종 이름에 액세스합니다. 이는 완전히 합리적인 접근법이지만 IME를 사용하면 원하는 데이터로 인해 특정 방식으로 쿼리를 수행 한 상황이 발생합니다 사용 – 당신은 그냥 돌아 왔을 때, 그 메타 정보가 손실 IEnumerable<Dog>– 쿼리가 될 수 있습니다 기대 당신이 (말)를 사용하는 Breed대신 Owner등 일부로드 옵션으로 인해,하지만 당신은 잊지 및 기타 속성을 사용하기 시작하면, 앱이 작동 할 수 있지만, 원래 예상했던 것만 큼 효율적이지 않습니다. 물론, 나는 쓰레기 또는 과다 최적화 등을 이야기 할 수 있습니다 …


답변

내 2 센트의 가치를 추가하기 위해 🙂 최근에 익명의 객체를 처리하는 방법을 배웠습니다. .NET 4 프레임 워크를 대상으로 할 때만 사용할 수 있으며 System.Web.dll에 대한 참조를 추가 할 때만 사용할 수 있지만 매우 간단합니다.

...
using System.Web.Routing;
...

class Program
{
    static void Main(string[] args)
    {

        object anonymous = CallMethodThatReturnsObjectOfAnonymousType();
        //WHAT DO I DO WITH THIS?
        //I know! I'll use a RouteValueDictionary from System.Web.dll
        RouteValueDictionary rvd = new RouteValueDictionary(anonymous);
        Console.WriteLine("Hello, my name is {0} and I am a {1}", rvd["Name"], rvd["Occupation"]);
    }

    private static object CallMethodThatReturnsObjectOfAnonymousType()
    {
        return new { Id = 1, Name = "Peter Perhac", Occupation = "Software Developer" };
    }
}

System.Web.dll에 대한 참조를 추가하려면 rushonerok의 조언 을 따라야 합니다. [프로젝트] 대상 프레임 워크가 “.NET Framework 4 클라이언트 프로파일”이 아닌 “.NET Framework 4″인지 확인하십시오.


답변

속임수없이 익명의 유형을 반환 할 수 없습니다.

C #을 사용하지 않는 경우 원하는 유형 (구체적인 유형없이 여러 데이터를 반환)을 Tuple이라고합니다.

여기표시된 것을 사용하여 C # 튜플 구현이 많이 있으며 코드는 다음과 같이 작동합니다.

public IEnumerable<Tuple<Dog,Breed>> GetDogsWithBreedNames()
{
    var db = new DogDataContext(ConnectString);
    var result = from d in db.Dogs
                 join b in db.Breeds on d.BreedId equals b.BreedId
                 select new Tuple<Dog,Breed>(d, b);

    return result;
}

그리고 전화 사이트에서 :

void main() {
    IEnumerable<Tuple<Dog,Breed>> dogs = GetDogsWithBreedNames();
    foreach(Tuple<Dog,Breed> tdog in dogs)
    {
        Console.WriteLine("Dog {0} {1}", tdog.param1.Name, tdog.param2.BreedName);
    }
}


답변

다음과 같이 할 수 있습니다.


public System.Collections.IEnumerable GetDogsWithBreedNames()
{
    var db = new DogDataContext(ConnectString);
    var result = from d in db.Dogs
                 join b in db.Breeds on d.BreedId equals b.BreedId
                 select new
                        {
                            Name = d.Name,
                            BreedName = b.BreedName
                        };
    return result.ToList();
}


답변

ToList()먼저 메소드 를 사용 하여 데이터베이스에서 행을 가져온 다음 항목을 클래스로 선택해야합니다. 이 시도:

public partial class Dog {
    public string BreedName  { get; set; }}

List<Dog> GetDogsWithBreedNames(){
    var db = new DogDataContext(ConnectString);
    var result = (from d in db.Dogs
                  join b in db.Breeds on d.BreedId equals b.BreedId
                  select new
                  {
                      Name = d.Name,
                      BreedName = b.BreedName
                  }).ToList()
                    .Select(x=>
                          new Dog{
                              Name = x.Name,
                              BreedName = x.BreedName,
                          }).ToList();
return result;}

따라서 트릭이 먼저ToList() 입니다. 즉시 쿼리하여 데이터베이스에서 데이터를 가져옵니다. 두 번째 요령은 항목을 선택하고 객체 이니셜 라이저사용하여 항목이로드 된 새 객체를 생성하는 것입니다.

도움이 되었기를 바랍니다.


답변

C # 7에서는 이제 tuples!를 사용할 수 있습니다. 결과를 반환하기 위해 클래스를 만들 필요가 없습니다.

다음은 샘플 코드입니다.

public List<(string Name, string BreedName)> GetDogsWithBreedNames()
{
    var db = new DogDataContext(ConnectString);
    var result = from d in db.Dogs
             join b in db.Breeds on d.BreedId equals b.BreedId
             select new
             {
                Name = d.Name,
                BreedName = b.BreedName
             }.ToList();

    return result.Select(r => (r.Name, r.BreedName)).ToList();
}

그래도 System.ValueTuple nuget 패키지를 설치해야 할 수도 있습니다.