2017-01-12 16 views
0

Linq to SQL Concat/Unionがカスタムクラスで動作しません。Linq to SQL Concat/Unionがカスタムクラスで機能しない

カスタムクラス

public class CustomClass 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public List<Accesses> Accesses { get; set; } 
} 

連合:

The 'Distinct' operation cannot be applied to the collection ResultType of the specified argument.\r\nParameter name: argument

IQueryable<CustomClass> objQuery = context.Users  
    .Where(W => W.Auth == true) 
    .Select(S => new CustomClass() 
    { 
     FirstName = S.FirstName, 
     LastName = S.LastName, 
     Accesses = context.AuthFalse 
        .Where(W => W.UID = S.ID) 
        .Select(S1 => new Accesses() 
        { 
         AccessesID = S1.AccessesID,             
        }) 
        .ToList(), 
    }) 
    .Union(context.Users  
     .Where(W => W.Auth == true)        
     .Select(S => new CustomClass() 
     { 
      FirstName = S.FirstName, 
      LastName = S.LastName, 
      Accesses = context.AuthTrue 
         .Where(W => W.UID = S.ID) 
         .Select(S1 => new Accesses() 
         { 
          AccessesID = S1.AccessesID,             
         }) 
         .ToList(), 
     }) 
    ); 

私は次のエラーを得たとき、私は上記のクエリを実行しますCONCAT

IQueryable<CustomClass> objQuery = context.Users  
    .Where(W => W.Auth == true) 
    .Select(S => new CustomClass() 
    { 
     FirstName = S.FirstName, 
     LastName = S.LastName, 
     Accesses = context.AuthFalse 
        .Where(W => W.UID = S.ID) 
        .Select(S1 => new Accesses() 
        { 
         AccessesID = S1.AccessesID,             
        }) 
        .ToList(), 
    }) 
    .Concat(context.Users  
     .Where(W => W.Auth == true)        
     .Select(S => new CustomClass() 
     { 
      FirstName = S.FirstName, 
      LastName = S.LastName, 
      Accesses = context.AuthTrue 
         .Where(W => W.UID = S.ID) 
         .Select(S1 => new Accesses() 
         { 
          AccessesID = S1.AccessesID,             
         }) 
         .ToList(), 
     }) 
    ); 

私は、次のエラーを得た上でクエリを実行:

{"The nested query is not supported. Operation1='UnionAll' Operation2='MultiStreamNest'"}

最後に、私は何をしたいユーザーテーブルの認証フィールドが真である場合ということですよりAuthTrueテーブルからデータを取得したい場合は、のリストフィールドに保存したい場合はAuthフィールドは、よりです。私はAuthFalseテーブルからのデータを得たいとリストフィールドに保存したいと思います。

これは、すべて単一クエリまたは最大2〜3クエリで実行します。

ありがとうございました。

+0

おそらくあなたは、このような連結方式の試行あなたを書き換える必要があります。ユーザーで始まるが、その後2左はuser.Authフィールドと適切な右のマッチによるフィルタリングを追加AuthFalseとAuthTrueに参加しない、匿名を選択しますuser.Id、user.LastName、user.FirstName + AuthFalse一致またはAuthTrue一致のいずれかのクラス。この段階では、キャストされたToEnumerableによってクエリ可能でなければならず、すべてが適切なグループ化+選択です。 –

+0

@VitaliyKalinin、ありがとう、あなたはいくつかのコードスニペットを提供していただけますか?なぜなら、あなたが実装するために言っていることを理解していないからです。 –

答えて

1

あなたはあなたにこのような連結方式の試行書き換える必要があります。ユーザー 2で 1. [スタート後2左はAuthFalseとAuthTrueに参加しない 3. user.Authフィールドによるフィルタリングし、適切な右のマッチを追加 4.ん]を選択user.Id、user.LastName、user.FirstName + AuthFalse一致またはAuthTrue一致のいずれかで匿名クラスに追加します。この段階では、キャストされたToEnumerable によって照会可能でなければなりません。5.その後、すべてが適切なグループ化+選択になります。ここで

が、これは完全なユニットテストステップである:

public class CustomClass 
    { 
     public string FirstName { get; set; } 
     public string LastName { get; set; } 
     public List<CustomAccesses> Accesses { get; set; } 
    } 

    public class CustomAccesses 
    { 
     public int Rights { get; set; } 
    } 


    public class Accesses 
    { 
     public Guid ID { get; set; } 
     public Guid UID { get; set; } 
     public int Rights { get; set; } 
    } 

    public class User 
    { 
     public Guid ID { get; set; } 
     public string FirstName { get; set; } 
     public string LastName { get; set; } 
     public bool Auth { get; set; } 
    } 

    [TestFixture] 
    public class QueryTests 
    { 
     private static readonly User TrueUser = new User 
     { 
      ID = Guid.NewGuid(), 
      FirstName = "TrueFirstName", 
      LastName = "TrueLastName", 
      Auth = true 
     }; 

     private static readonly User FalseUser = new User 
     { 
      ID = Guid.NewGuid(), 
      FirstName = "FalseFirstName", 
      LastName = "FalseLastName", 
      Auth = false 
     }; 

     private static readonly User[] DbUsersMock = 
     { 
      TrueUser, 
      FalseUser 
     }; 

     private static readonly Accesses[] DbAuthTrueMock = 
     { 
      new Accesses 
      { 
       ID = Guid.NewGuid(), 
       UID = TrueUser.ID, 
       Rights = 1 
      }, 
      new Accesses 
      { 
       ID = Guid.NewGuid(), 
       UID = TrueUser.ID, 
       Rights = 2 
      } 
     }; 

     private static readonly Accesses[] DbAuthFalseMock = 
     { 
      new Accesses 
      { 
       ID = Guid.NewGuid(), 
       UID = FalseUser.ID, 
       Rights = -1 
      }, 
      new Accesses 
      { 
       ID = Guid.NewGuid(), 
       UID = FalseUser.ID, 
       Rights = -2 
      } 
     }; 

     [Test] 
     public void Test() 
     { 
      var users = DbUsersMock.AsQueryable(); 

      var authTrue = DbAuthTrueMock.AsQueryable(); 

      var authFalse = DbAuthFalseMock.AsQueryable(); 


      var result = users 
       .GroupJoin(
        authTrue, 
        u => u.ID, 
        ta => ta.UID, 
        (user, accesses) => new 
        { 
         user, 
         accesses = accesses.DefaultIfEmpty() 
        } 
       ) 
       .SelectMany(
        ua => ua 
         .accesses 
         .Select(
          trueAccess => new 
          { 
           ua.user, 
           trueAccess 
          } 
         ) 
       ) 
       .GroupJoin(
        authFalse, 
        ua => ua.user.ID, 
        fa => fa.UID, 
        (userAccess, accesses) => new 
        { 
         userAccess, 
         accesses = accesses.DefaultIfEmpty() 
        } 
       ) 
       .SelectMany(
        uaa => uaa 
         .accesses 
         .Select(
          falseAccess => new 
          { 
           uaa.userAccess.user, 
           uaa.userAccess.trueAccess, 
           falseAccess 
          } 
         ) 
       ) 
       .Where(
        uaa => uaa.user.Auth 
         ? uaa.trueAccess != null 
         : uaa.falseAccess != null 
       ) 
       .Select(
        uaa => new 
        { 
         uaa.user.ID, 
         uaa.user.FirstName, 
         uaa.user.LastName, 
         AccessID = uaa.user.Auth 
          ? uaa.trueAccess.ID 
          : uaa.falseAccess.ID, 
         Rights = uaa.user.Auth 
          ? uaa.trueAccess.Rights 
          : uaa.falseAccess.Rights 
        } 
       ) 
       .OrderBy(uaa => uaa.ID) 
       .AsEnumerable() 
       .GroupBy(uaa => uaa.ID) 
       .Select(
        g => new CustomClass 
        { 
         FirstName = g.First().FirstName, 
         LastName = g.First().LastName, 
         Accesses = g 
          .GroupBy(uaa => uaa.AccessID) 
          .Select(
           uaa => new CustomAccesses 
           { 
            Rights = uaa.First().Rights 
           } 
          ) 
          .ToList() 
        } 
       ) 
       .ToArray(); 

      Assert.That(result.Length, Is.EqualTo(DbUsersMock.Length)); 
     } 
    } 
+0

ありがとうございます。クエリを実行するAsEnumerable()メソッドを使用しましたが、クエリを実行する必要はありません。そのため、検索キーワード条件を追加し、その上に施設のような並べ替えをする必要があります。私はそれをメモリ上ではなくデータベース上でやりたい。 –

+0

私はLinqToSqlがあなたの要件を適切に処理できる場所にAsEnumerable()を配置しました。あなたの説明が不完全な場合は、ソリューションを完成させる準備ができているはずです。 –

+0

実際、このコードは私がコメントとして投稿した説明のためのスニペットです。答えに私のコメントをコピーしてコピーします。 –

0

あなたは多くの方法でそれを行うことができます。これを行う簡単な方法は次のとおりです。 2つのリストをとります.1つはTRUE、もう1つはFALSEです。結果のリストで、ADDRANGEメソッドを使用します。 このメソッド(ADDRANGE)は、リストを操作しているときにのみ機能します。

例:

var listTrue = ctx.Users.Where(...).Select(s=> new CustomClass{...}).ToList(); 
var listFalse = ctx.Users.Where(...).Select(s=> new CustomClass{...}).ToList(); 
var result = new List<CustomClass>(); 
result.AddRange(listTrue); 
result.AddRange(listFalse); 
return result;