使用左连接获取不适当的输出

Getting inappropriate output with left join

我正在尝试获取变体列表,并且对于每个变体都获取所有 subvariants list,而不管子变体适用于何处 特别是 Test say 100。这是示例数据:

Id      TestId    SourceSubVariantId   TargetSubVariantId   DiffPerc
114      100           66              67                   100.00
115      100           67              68                   100.00
116      100           70              71                   99.99

我有 3 个变体 1 的子变体:

Id=66,Name=Abc
Id=68,Name=Pqr
Id=69,Name=xyz

我有 3 个变体 2 的子变体 :

Id=70,Name=lmn
Id=71,Name=xxx
Id=72,Name=hhh

但是请注意,在我的输出中,我正在为 Variant1 CustomSubvariantList:

中的 Variants 2 subvariants list 获取所有 Id as 0

数据模型:

public class Variants
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Type { get; set; }
        public virtual ICollection<SubVariants> SubVariants { get; set; }
    }

    public class SubVariants
    {
        public int Id { get; set; }
        public int VariantId { get; set; }
        public string Name { get; set; }
        public virtual Variants Variants { get; set; }
        public virtual ICollection<TestOperation> TestOperation { get; set; }
        public virtual ICollection<TestOperation> TestOperation1 { get; set; }
    }

        public class TestOperation
    {
        public int Id { get; set; }
        public Nullable<int> TestId { get; set; }
        public int SourceSubVariantId { get; set; }
        public int TargetSubVariantId { get; set; }
        public decimal DiffPerc { get; set; }
        public virtual SubVariants SubVariants { get; set; }
        public virtual SubVariants SubVariants1 { get; set; }
                public virtual Test Test { get; set; }
    }

查询:

int testId=100;
var query =
      from v in context.Variants 
      where v.Type  == "Add"
      select new
      {
           ParentVariant = v.Name,
           Type = v.Method,
           CustomSubvariantList =
           (
                from svName in context.SubVariants.Select(sv => sv.Name).Distinct()
                join x in
                (
                     from sv in v.SubVariants 
                     from to in sv.TestOperation 
                     where to.TestId == testId
                     orderby sv.Id
                     select new
                     {
                          sv.Name,
                          to.DiffPerc,
                          SourceId = (int?)to.SubVariants.Id,
                          TargetID=(int?)to.SubVariants1.Id
                     }
                 )
                 on svName equals x.Name into g  
                 from x in g.DefaultIfEmpty()
                 orderby x.SourceId
                 select new
                 {
                      SourceId=x.SourceId ?? 0,
                      TargetId=x.TargetID ?? 0,
                      Name = svName,
                      DiffPerc = x.DiffPerc
                 }
             ).ToList()
         };

更新: 根据评论,这是示例输入和预期输出:

案例 1:当所有父变体的子变体名称不同时

变体:

Id      Name       Type   CategoryId
11      Variant1    Add     1
12      Variant2    Add     1
13      Variant3    Add     1
14      Variant4    Add     1

子变量:

Id     VariantId     Name
66      11           Abc
67      11           PQR
68      11           Xyz

70      12           lmn
71      12           xxx
72      12           hhh

试运行:

Id      TestId    SourceSubVariantId   TargetSubVariantId   DiffPerc
114      100           66               67                  10.00
115      100           67               68                  20.00

114      100           70               71                  40.00
115      100           71               72                  50.00

预期输出

情况 2:当子变体名称在所有父变体中都相同时:

子变量:

Id     VariantId     Name
66      11           Abc
67      11           PQR
68      11           Xyz

70      12           Abc
71      12           PQR
72      12           Xyz

预期输出

我们在聊天中进行了一些讨论,直到我明白了你想要什么。

这是代码:

    class Program
{
    static void Main(string[] args)
    {
        VariantsEntities db=new VariantsEntities();

        var queryResult = db.Variants.AsEnumerable().Select(x => new PageViewModel
        {
            ParentVariant = x.Name,
            Type = x.Type,
            CustomSubvariantList = GetCustomSubVariants(x.Id,db).ToList()
        }).ToList();


        var jsonObj = JsonConvert.SerializeObject(queryResult);
        Console.WriteLine(jsonObj);
        Console.ReadKey();
    }

    private static IEnumerable<Customsubvariantlist> GetCustomSubVariants(int variantId, VariantsEntities db)
    {
        var subVariants = db.SubVariants.ToList();

        foreach (var subVariant in subVariants)
        {
            var obj=new Customsubvariantlist();
            obj.Name = subVariant.Name;

            var testOpTarget = db.TestOperations
                .FirstOrDefault(x => x.TargetSubVariantId == subVariant.Id);
            var testOpSource = db.TestOperations
                .FirstOrDefault(x => x.SourceSubVariantId == subVariant.Id);

            if (subVariant.VariantId == variantId)
            {
                obj.Value = testOpTarget == null ? 
                    testOpSource?.SourceValue : testOpTarget?.TargetValue;
                obj.DiffPerc = testOpTarget?.DiffPerc;
            }
            else
            {
                obj.Value = null;
                obj.DiffPerc = null;
            }
            yield return obj;
        }

    }
}

您只需要替换DbContext 名称,然后进行测试即可。

这是结果:

    [
  {
    "ParentVariant": "Variant1",
    "Type": "Add",
    "CustomSubvariantList": [
      {
        "Name": "Abc",
        "Value": 200,
        "DiffPerc": null
      },
      {
        "Name": "Pqr",
        "Value": 300,
        "DiffPerc": 100.0
      },
      {
        "Name": "xyz",
        "Value": 500,
        "DiffPerc": 200.0
      },
      {
        "Name": "lmn",
        "Value": null,
        "DiffPerc": null
      },
      {
        "Name": "xxx",
        "Value": null,
        "DiffPerc": null
      },
      {
        "Name": "hhh",
        "Value": null,
        "DiffPerc": null
      }
    ]
  },
  {
    "ParentVariant": "Variant2",
    "Type": "Add",
    "CustomSubvariantList": [
      {
        "Name": "Abc",
        "Value": null,
        "DiffPerc": null
      },
      {
        "Name": "Pqr",
        "Value": null,
        "DiffPerc": null
      },
      {
        "Name": "xyz",
        "Value": null,
        "DiffPerc": null
      },
      {
        "Name": "lmn",
        "Value": 1000,
        "DiffPerc": null
      },
      {
        "Name": "xxx",
        "Value": 2000,
        "DiffPerc": 1000.0
      },
      {
        "Name": "hhh",
        "Value": 4000,
        "DiffPerc": 2000.0
      }
    ]
  }
]

您可以从 here 下载示例项目。这个项目是用你发给我的示例数据库完成的,数据库优先也是如此,一些道具或表格可能有不同的名称,请在你的项目中移动代码之前检查这一点。

基本上我做了什么:

  1. 创建了一个新的控制台应用程序项目

  2. 我从你的 json 对象中得到了模型(我复制了 json 对象并将其粘贴到 class 中,使用(vs 菜单)编辑 - > 过去特别 -> 过去 JSON 为 类。

  3. 因为你想要每个 Varian 的所有 SubVariants,我创建了一个单独的方法来处理你创建 CustomSubVariantList 的规则。在这种方法中,我迭代抛出所有 SubVariants 并根据您的条件创建对象。

更新: 您在一次查询中的解决方案:

static void Main(string[] args)
    {
        VariantsEntities db = new VariantsEntities();

        var result = from x in db.Variants                        
                     select new PageViewModel
                     {
                         ParentVariant = x.Name,
                         Type = x.Type,
                         CustomSubvariantList = (from z in db.SubVariants
                                                 let testOpTarget=z.TestOperations1
                                                        .FirstOrDefault(q=>q.TargetSubVariantId==z.Id)
                                                 let testOpSource=z.TestOperations
                                                        .FirstOrDefault(q=>q.SourceSubVariantId==z.Id)
                                                 select new Customsubvariantlist
                                                 {
                                                     Name = z.Name,
                                                     Value = x.Id==z.VariantId? 
                                                             testOpTarget.TargetValue??
                                                             testOpSource.SourceValue:null,
                                                     DiffPerc = x.Id==z.VariantId? 
                                                                testOpTarget.DiffPerc:null
                                                 }).ToList()
                     };

        var json = JsonConvert.SerializeObject(result.ToList());
        Console.WriteLine(json);
        Console.ReadKey();
    }

此查询产生与上述方法相同的结果。 请让我知道您是否需要!!

更新:这是案例 2 的查询

 var result = from x in db.Variants
            select new PageViewModel
            {
                ParentVariant = x.Name,
                Type = x.Type,
                CustomSubvariantList = (from z in db.SubVariants.GroupBy(g => g.Name)
                    .Select(g => g.FirstOrDefault(d => d.VariantId == x.Id) ?? g.FirstOrDefault())
                    let testOpTarget = z.TestOperations1
                        .FirstOrDefault(q => q.TargetSubVariantId == z.Id)
                    let testOpSource = z.TestOperations
                        .FirstOrDefault(q => q.SourceSubVariantId == z.Id)
                    select new Customsubvariantlist
                    {
                        Name = z.Name,
                        SubVariantId = z.Id,
                        CombineName =(z.TestOperations.Any() || z.TestOperations1.Any())? 
                                      testOpTarget.TargetValue.HasValue? 
                                      testOpTarget.SubVariant.Name+" to "+testOpTarget.SubVariant1.Name : null: "Undefined",
                        Value = x.Id == z.VariantId
                            ? testOpTarget.TargetValue ??
                              testOpSource.SourceValue
                            : null,
                        DiffPerc = x.Id == z.VariantId
                            ? testOpTarget.DiffPerc
                            : null
                    }).OrderBy(k => k.SubVariantId).ToList()
            };

这是您的查询的 "variant".. 它提取所有 SubVariants 每个 Variant(s) 的顺序,因为它们在 table SubVariants 中(通过它们的自动种子 Sql Server Identity Id),不考虑涉及的 TestOperation 并避免重复作为您的预期输出。

不幸的是,不可能始终将所有子变量指定为源和目标子变量,因为此信息取决于测试操作,实际上测试操作决定子变量是 "source" 还是 "target"。因此,如果某些子变体未包含在测试操作 records/entity 中,则它们不能作为源或目标出现。解决方法可能是附加到返回的匿名类型 "Name" 属性 旁边,还有 "Id SubVar"

我添加了 2 个 DTO,因为 entity framework 不允许使用 distinct().ToList() 方法来保留顺序和应用自定义不同规则,所以我添加了一个步骤以从 Link 传递到Link 处的 EF 通过 dto 对象来对象,并以这种方式使应用不同的自定义规则成为可能..

    public class CustomerVariantDTO
    {
        public String Type;
        public String ParentVariant;
        public IEnumerable<CustomerSubVariantDTO> CustomSubvariantList;
    }

    public class CustomerSubVariantDTO
    {
        public int? VariantId;
        public int? SubVariantId;
        public int? SourceId;
        public int? TargetId;
        public String Name;
        public Decimal? DiffPerc;
    }

    sealed class CustomerSubVariantDTOComparer : IEqualityComparer<CustomerSubVariantDTO>
    {
        public int GetHashCode(CustomerSubVariantDTO obj)
        {
            return 0;
        }

        public bool Equals(CustomerSubVariantDTO x, CustomerSubVariantDTO y)
        {
            return x.SourceId == y.SourceId &&
                   x.TargetId == y.TargetId &&
                   x.Name == y.Name &&
                   x.DiffPerc == y.DiffPerc;

        }
    }


    public void DoTestOfCustomerVariantDTO()
    {
        int testId = 1;
        using (var context = new VariantsEntities())
        {
            var query =
              (from v in context.Variants
               where v.Type == "Add"
               select new CustomerVariantDTO
               {
                   ParentVariant = v.Name,
                   Type = v.Type,
                   CustomSubvariantList =
                   (
                     from sv in context.SubVariants.Select(sv => sv)
                     join x in
                     (
                         from svparent in v.SubVariants
                         from to in svparent.TestOperation
                         where to.TestId == testId
                         select new
                         {
                             svparent.Name,
                             to.DiffPerc,
                             SourceId = (int?)to.SubVariants.Id ?? 0,
                             TargetId = (int?)to.SubVariants1.Id ?? 0
                         }
                     )
                     on sv.Name equals x.Name into g
                     from x in g.DefaultIfEmpty()
                     select new CustomerSubVariantDTO{
                         VariantId = sv.VariantId,
                         SubVariantId = sv.Id,
                         SourceId = (int?)x.SourceId ?? sv.TestOperation.Select(to => to.SourceSubVariantId).FirstOrDefault(),
                         TargetId = (int?)x.TargetId ?? sv.TestOperation.Select(to => to.TargetSubVariantId).FirstOrDefault(),
                         Name = sv.Name,
                         DiffPerc = x.DiffPerc
                     }
                  ).OrderBy(csv => new { csv.VariantId, csv.SubVariantId })
               }).ToList();

            var listCustomVariants =
                query.Select(v => new{
                    Type = v.Type,
                    ParentVariant = v.ParentVariant,
                    CustomSubvariantList = v.CustomSubvariantList.Distinct(new CustomerSubVariantDTOComparer()).ToList()
                });

            foreach (var item in listCustomVariants){
                Console.WriteLine($"Type: {item.Type} - ParentVariant: {item.ParentVariant} ");
                foreach (var csubvar in item.CustomSubvariantList)
                    Console.WriteLine($"SourceId: {csubvar.SourceId} - TargetiId: {csubvar.TargetId} - NAme: {csubvar.Name} - DiffPerc: {csubvar.DiffPerc} ");
            }
        }
    }