Получение неулокального вывода с левым соединением

Я пытаюсь получить список вариантов и для каждого из этих вариантов получить все 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

Но обратите внимание, что в моем выпуске я получаю все Id as 0 для Variants 2 subvariants list в Variant1 CustomSubvariantList:

введите описание изображения здесь

Модель данных:

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; }
    }

Query:

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

Ожидаемый результат:

Ответы

Ответ 1

У нас были некоторые обсуждения в чате, пока я не понял, чего вы хотите.

это код:

    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
      }
    ]
  }
]

Из здесь вы можете загрузить образец проекта. Этот проект был выполнен с образцовой базой данных, которую вы мне отправили, так что Database First и возможно, что некоторые реквизиты или таблицы имеют другое имя, пожалуйста, проверьте это, прежде чем перемещать код в своем проекте.

В основном, что я сделал:

  • создан новый проект консольного приложения

  • Я получил модель из вашего json-объекта (я скопировал объект json и выполнил его в классе, используя (vs menu) Edit → Past Special → Past JSON as Classes.

  • Поскольку вы хотите все SubVariants для каждого Varian, я создал отдельный метод для обработки правил, которые вы создали для создания CustomSubVariantList. В этом методе я перебираю все субварианты и создаю базу объектов на ваших условиях.

Обновление: ваше решение в одном запросе:

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()
            };

Ответ 2

Это "вариант" вашего запроса. он извлекает все SubVariants за Variant(s), упорядоченные, как они есть в таблице SubVariants (по их авторизованному идентификатору идентификатора сервера Sql), независимо от TestOperation, участвующих и избегающих дублирует ваши ожидаемые результаты.

К сожалению, не всегда можно указать все подварианты, которые обозначаются как субвариант источника и tartget, потому что эта информация зависит от тестовой операции, на самом деле testop решает, является ли subvar "источником" или "целевым". Таким образом, если некоторые подварианты не включены в testoperations records/entity, то они не могут отображаться как источник или цель.. Обходным решением может быть присоединение, рядом с атрибутом "Имя" анонимного типа, а также "Id SubVar"

Я добавил 2 DTO, потому что инфраструктура сущности не позволяет использовать метод distinct().ToList() для сохранения порядка и применения настраиваемого отдельного правила, поэтому я добавил еще один шаг, чтобы перейти от ссылки к 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} ");
            }
        }
    }