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 -

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 详细信息的附加连接,所以我尝试添加 -

                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

我认为这些连接没有被正确链接。

在第二个连接中,第二个参数引用外部集合。这将是第一个 join 的投影匿名类型new { User = user, SchemeName = schemeName })

假设在 User 类上有一个属性 LifeAssurance,那么我猜你想要基于来自用户对象的该属性进行第二次连接,如下所示:

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”

对于第二个内连接查询

用户:“用户 1”,养老金:“方案 1”,人寿保险:“方案 2”

用户:“用户 2”,养老金:“方案 1”,人寿保险:“方案 2”

对于左连接查询

用户:“用户 1”,养老金:“方案 1”,人寿保险:“方案 2”

用户:“用户 2”,养老金:“方案 1”,人寿保险:“方案 2”

用户:“用户 3”,养老金:“方案 1”,人寿保险:“无人寿保险”

用户:“用户 4”,养老金:“无养老金”,人寿保险:“方案 2”

于 2013-01-15T20:20:49.623 回答