1

クエリに結合を追加することで、以前にいくつかの助けを得ました。同じクエリに実際に複数の結合を追加する必要があることに気付きましたが、(元の結合に基づいて)さまざまな方法を試しましたが、エラーが発生し続けます。

私はSchemeNameというモデルを持っています-

namespace TRS.Models
{
    public class SchemeName
    {
        [Key]
        public int SchemeNameID { get; set; }
        [Display(Name = "Scheme Name")]
        public string Name { get; set; }

        public virtual ICollection<Benefit> Benefits { get; set; }
    }
}

そして、それぞれがSchemeIDを持つ次の2つのような従業員福利厚生の複数のモデル-

namespace TRS.Models
{
    public class Pension
    {
        [Key]
        public string UserName { get; set; }
        public bool PensionRequired { get; set; }
        public int PensionSchemeNameID { get; set; }
        public int PensionProviderID { get; set; }
        public int PensionBenefitLevelID { get; set; }
        public decimal PensionEmployerCost { get; set; }
        public decimal PensionEmployeeCost { get; set; }

        public virtual PensionBenefitLevel PensionBenefitLevel { get; set; }

        [Required]
        public virtual User User { get; set; }
    }
}

namespace TRS.Models
{
    public class LifeAssurance
    {
        [Key]
        public string UserName { get; set; }
        public bool LifeAssuranceRequired { get; set; }
        public int LifeAssuranceSchemeNameID { get; set; }
        public int LifeAssuranceProviderID { get; set; }
        public string LifeAssuranceBenefitLevel { get; set; }
        public decimal LifeAssuranceEmployerCost { get; set; }
        public decimal LifeAssuranceEmployeeCost { get; set; }


        [Required]
        public virtual User User { get; set; }
    }
}

私のコントローラーには次のものがあります-

var trs = db.Users
                .Join(db.SchemeNames,
                user => user.Pension.PensionSchemeNameID, 
                schemeName => schemeName.SchemeNameID,
                (user, schemeName) => new { User = user, SchemeName = schemeName })
                .Where(a => UserIDs.Contains(a.User.UserName))
                .Select(a => new TRSViewModel
            { 
                UserName = a.User.UserName,
                FirstName = a.User.UserDetails.FirstName,
                LastName = a.User.UserDetails.LastName,
                Salary = a.User.UserDetails.Salary,
                PensionSchemeName = a.SchemeName.Name,

これはPensionSchemeNameを表示するのに最適ですが、LifeAssuranceSchemeName(およびその他)も表示する必要がありますが、前述したようにエラーが発生し続けます。LifeAssuranceSchemeNameの詳細を含むJoinを追加する必要があると思ったので、追加してみました-

                var trs = db.Users
                .Join(db.SchemeNames,
                user => user.Pension.PensionSchemeNameID, 
                schemeName => schemeName.SchemeNameID,
                (user, schemeName) => new { User = user, SchemeName = schemeName })
                .Join(db.SchemeNames,
                la => la.Pension.PensionSchemeNameID,
                schemeName => schemeName.SchemeNameID,
                (user, schemeName) => new { User = user, SchemeName = schemeName })
                .Where(a => UserIDs.Contains(a.User.UserName))
                .Select(a => new TRSViewModel

しかし、これは私にエラーを与えます-

エラー10「AnonymousType#1」に「Pension」の定義が含まれておらず、タイプ「AnonymousType#1」の最初の引数を受け入れる拡張メソッド「Pension」が見つかりませんでした(usingディレクティブまたはアセンブリ参照がありませんか?)

これらの追加の結合を追加する方法はありますか?

4

1 に答える 1

3

それらの結合は適切に連鎖されていないと思います。

2番目の結合では、2番目の引数は外部コレクションを参照します。これは、最初の結合から投影された匿名タイプになりnew { User = user, SchemeName = schemeName })ます。

UserクラスにプロパティLifeAssuranceがあるとすると、次のように、ユーザーオブジェクトからのそのプロパティに基づいて2番目の結合を実行する必要があると思います。

var trs = db.Users
            .Join(db.SchemeNames,
                 user => user.Pension.PensionSchemeNameID, 
                 schemeName => schemeName.SchemeNameID,
                 (user, schemeName) => new { User = user, 
                                             SchemeName = schemeName })
            .Join(db.SchemeNames,
                 x => x.User.LifeAssurance.LifeAssuranceSchemeNameID,
                 schemeName => schemeName.SchemeNameID,
                 (x, schemeName) => new { User = x.User, 
                                          PensionSchemeName = x.SchemeName, 
                                          LifeAssuranceSchemeName = schemeName })
            .Where(a => UserIDs.Contains(a.User.UserName))
            .Select(a => new TRSViewModel{
                          UserName = a.User.UserName,
                          FirstName = a.User.UserDetails.FirstName,
                          LastName = a.User.UserDetails.LastName,
                          Salary = a.User.UserDetails.Salary,
                          PensionSchemeName = a.PensionSchemeName.Name,
                          LifeAssuranceSchemeName = a.LifeAssuranceSchemeName.Name
            });

これは、クエリ構文で次のように記述できます(おそらく読みやすい):

var trs = from user in db.Users
          join pensionSchema in db.SchemeNames 
               on user.Pension.PensionSchemeNameID equals pensionSchema.SchemeNameID
          join lifeAssuranceSchema in db.SchemeNames 
               on user.LifeAssurance.LifeAssuranceSchemeNameID equals lifeAssuranceSchema.SchemeNameID
          where UserIds.Contains(user.UserName)
          select new TRSViewModel{
                      UserName = user.UserName,
                      FirstName = user.UserDetails.FirstName,
                      LastName = user.UserDetails.LastName,
                      Salary = user.UserDetails.Salary,
                      PensionSchemeName = pensionSchema.Name,
                      LifeAssuranceSchemeName = lifeAssuranceSchema.Name }

最後に、これらは内部結合であるため、年金または生命保険スキーマを持たないユーザーは返されません。左結合が必要な場合は、ここでuser.Pension.PensionSchemeNameID説明するアプローチのようなことを行うことができます(ただし、年金のないユーザーがいる場合、のような式はNullReferenceExceptionをスローするため、これは必要ないと思います)

var query =
      from user in db.Users
      from pensionScheme in db.SchemeNames
              .Where(s => s.SchemeNameID == user.Pension.PensionSchemeNameID)
              .DefaultIfEmpty()
      from lifeAssuranceScheme in db.SchemeNames
              .Where(s => s.SchemeNameID == user.LifeAssurance.LifeAssuranceSchemeNameID)
              .DefaultIfEmpty()
      select new { User = user, 
                   Pension = pensionScheme, 
                   LifeAssurance = lifeAssuranceScheme} 

メモリ内のコレクションで次のコードを使用してこれらのクエリをすばやくテストしましたが、エンティティフレームワークによってSQLに正しく変換する必要があります。

public class SchemeName
{
    public int SchemeNameID { get; set; }
    public string Name { get; set; }
}

public class Pension
{
    public int PensionSchemeNameID { get; set; }
}

public class LifeAssurance
{
    public int LifeAssuranceSchemeNameID { get; set; }
}

public class User
{
    public string Name { get; set; }
    public Pension Pension { get; set; }
    public LifeAssurance LifeAssurance { get; set; }
}

public static class db
{
    public static IEnumerable<User> Users = new List<User>() { 
            new User { Name = "User 1", 
                        Pension = new Pension { PensionSchemeNameID = 1 }, 
                        LifeAssurance = new LifeAssurance { LifeAssuranceSchemeNameID = 2 } },
            new User { Name = "User 2", 
                        Pension = new Pension { PensionSchemeNameID = 1 }, 
                        LifeAssurance = new LifeAssurance { LifeAssuranceSchemeNameID = 2 } },
            new User { Name = "User 3", 
                        Pension = new Pension { PensionSchemeNameID = 1 },
                        LifeAssurance = new LifeAssurance { LifeAssuranceSchemeNameID = -999 }},
            new User { Name = "User 4", 
                        Pension = new Pension { PensionSchemeNameID = -999 }, 
                        LifeAssurance = new LifeAssurance { LifeAssuranceSchemeNameID = 2 } }
    };
    public static IEnumerable<SchemeName> SchemeNames = new List<SchemeName>() { 
                new SchemeName{ SchemeNameID = 1, Name = "Scheme 1"  },
                new SchemeName{ SchemeNameID = 2, Name = "Scheme 2"  }
    };
}

    private void Run()
    {
        var innerJoinQuery1 = db.Users
                    .Join(db.SchemeNames,
                            user => user.Pension.PensionSchemeNameID,
                            schemeName => schemeName.SchemeNameID,
                            (user, schemeName) => new
                            {
                                User = user,
                                SchemeName = schemeName
                            })
                    .Join(db.SchemeNames,
                            x => x.User.LifeAssurance.LifeAssuranceSchemeNameID,
                            schemeName => schemeName.SchemeNameID,
                            (x, schemeName) => new
                            {
                                User = x.User,
                                PensionSchemeName = x.SchemeName,
                                LifeAssuranceSchemeName = schemeName
                            })
                    .Where(a => a.User.Name.StartsWith("User "))
                    .Select(a => new 
                    {
                        UserName = a.User.Name,
                        PensionSchemeName = a.PensionSchemeName.Name,
                        LifeAssuranceSchemeName = a.LifeAssuranceSchemeName.Name
                    });

        var innerJoinQuery2 = from user in db.Users
                     join pensionSchema in db.SchemeNames
                        on user.Pension.PensionSchemeNameID equals pensionSchema.SchemeNameID
                     join lifeAssuranceSchema in db.SchemeNames
                        on user.LifeAssurance.LifeAssuranceSchemeNameID equals lifeAssuranceSchema.SchemeNameID
                     where user.Name.StartsWith("User ")
                     select new
                               {
                                   UserName = user.Name,
                                   PensionSchemeName = pensionSchema.Name,
                                   LifeAssuranceSchemeName = lifeAssuranceSchema.Name
                               };

        var lefJoinQuery =
                      from user in db.Users
                      from pensionScheme in db.SchemeNames
                              .Where(s => s.SchemeNameID == user.Pension.PensionSchemeNameID)
                              .DefaultIfEmpty()
                      from lifeAssuranceScheme in db.SchemeNames
                              .Where(s => s.SchemeNameID == user.LifeAssurance.LifeAssuranceSchemeNameID)
                              .DefaultIfEmpty()
                      select new
                      {
                          UserName = user.Name,
                          PensionSchemeName = pensionScheme != null ? pensionScheme.Name : "No Pension",
                          LifeAssuranceSchemeName = lifeAssuranceScheme != null ? lifeAssuranceScheme.Name : "No Life Assurance"
                      }; 

        foreach (var result in innerJoinQuery1)
            Print(result.UserName, result.PensionSchemeName, result.LifeAssuranceSchemeName);

        Console.WriteLine();

        foreach (var result in innerJoinQuery2)
            Print(result.UserName, result.PensionSchemeName, result.LifeAssuranceSchemeName);

        Console.WriteLine();

        foreach (var result in lefJoinQuery)
            Print(result.UserName, result.PensionSchemeName, result.LifeAssuranceSchemeName);

        Console.WriteLine();

        Console.ReadKey();
    }

    private void Print(string user, string pension, string lifeAssurance)
    {
        Console.WriteLine(String.Format("User: '{0}', Pension: '{1}', Life Assurance: '{2}'", user, pension, lifeAssurance));
    }
}

期待される出力を生成します。

最初の内部結合クエリの場合

ユーザー:'ユーザー1'、年金:'スキーム1'、生命保険:'スキーム2'

ユーザー:'ユーザー2'、年金:'スキーム1'、生命保険:'スキーム2'

2番目の内部結合クエリの場合

ユーザー:'ユーザー1'、年金:'スキーム1'、生命保険:'スキーム2'

ユーザー:'ユーザー2'、年金:'スキーム1'、生命保険:'スキーム2'

左結合クエリの場合

ユーザー:'ユーザー1'、年金:'スキーム1'、生命保険:'スキーム2'

ユーザー:'ユーザー2'、年金:'スキーム1'、生命保険:'スキーム2'

ユーザー:'ユーザー3'、年金:'スキーム1'、生命保険:'生命保険なし'

ユーザー:'ユーザー4'、年金:'年金なし'、生命保険:'スキーム2'

于 2013-01-15T20:20:49.623 に答える