Entity Framework, возвращающая отдельную запись

У меня есть PC Enity, у которого есть некоторые свойства, я хотел бы вернуть список отдельных объектов (ПК или сложный тип или что-то еще) на основе свойства, чтобы привязать его к серверным элементам управления, таким как DropDownList. И поскольку мой метод, расположенный в BLL, я не могу вернуть анонимный тип, поэтому я создал Branch ComplexType, который имеет два peroperties.

Я написал так, но у него есть повторяющиеся записи:

List<Branch> result = ( from p in _context.PCs
                        where p.UserId== userId
                        select new Branch()
                                   {
                                      BranchId= p.BranchId,
                                      BranchName=p.BranchName
                                   }).Distinct().ToList();

Изменить: Спасибо всем, это сработало:

List<PC> result = _context.PCs
                  .GroupBy(p=>p.BranchName , p.BranchId})
                  .select(g=>g.First())
                  .ToList();

Ответ 1

это приведет к возврату отдельных строк для всех столбцов в инструкции select. Если вы хотите, чтобы отдельные строки для определенного столбца указывали только конкретный столбец

List<Branch> result = ( from p in _context.PCs
                        where p.UserId== userId
                        select new Branch()
                                   {
                                      BranchId= p.BranchId,
                                    }).Distinct().ToList();

Если вы хотите получить разные значения на основе нескольких столбцов, вам необходимо создать группу, а затем выбрать первое значение из этой группы. В этом случае вы не будете использовать Distinct, например

List<Branch> distinctResult = _context.PCs
  .GroupBy(p => new Branch {p.BranchId, p.BranchName} )
  .Select(g => g.First())
  .ToList(); 

Ответ 2

Вы получаете дубликаты, потому что Distinct() не может распознать два ваших сложных объекта Branch как идентичные их свойствам. Он просто сравним для равенства объектов, который вернет false (потому что вы создаете два разных объекта, но с одинаковыми значениями).

Вы можете использовать Distinct (IQueryable, IEqualityComparer), чтобы предоставить свой собственный Comparer или реализовать IEquatable.

Ответ 3

Я не могу воспроизвести проблему (протестирован с SQL Server 2008 R2 и EF 4.1/DbContext). Запрос в вашем вопросе...

List<Branch> result = ( from p in _context.PCs
                        where p.UserId== userId
                        select new Branch()
                        {
                            BranchId = p.BranchId,
                            BranchName = p.BranchName
                        })
                        .Distinct()
                        .ToList();

... генерирует следующий SQL:

SELECT 
[Distinct1].[C1] AS [C1],
[Distinct1].[BranchId] AS [BranchId],
[Distinct1].[BranchName] AS [BranchName]
FROM ( SELECT DISTINCT 
       [Extent1].[BranchId] AS [BranchId], 
       [Extent1].[BranchName] AS [BranchName], 
       1 AS [C1]
       FROM [dbo].[PCs] AS [Extent1]
) AS [Distinct1]

Это DISTINCT для обоих столбцов, и я получаю ожидаемый отличный результат - никаких дубликатов в BranchId и BranchName.

Ответ 4

Это работает для меня.

1.

class RolBaseComparer:IEqualityComparer<RolBase>
{
    public RolBaseComparer()
    {

    }

    public bool Equals(RolBase x, RolBase y)
    {
        if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
        {
            return false;
        }

        if (Object.ReferenceEquals(x, y))
        {
            return true;
        }

        return x.Id.Equals(y.Id) &&
                x.Nombre.Equals(y.Nombre);
    }

    public int GetHashCode(RolBase obj)
    {
        return obj.Id.GetHashCode() ^ obj.Nombre.GetHashCode();
    }
}

2.

var ResultQuery = (from ES in DbMaster.Estudiantes
                               join I in DbMaster.Inscripciones on ES.strCedula equals I.strCedEstud
                               join C in DbMaster.Carreras on I.strCodCarrera equals C.strCodigo
                               where ES.strCedula.Equals(Cedula)
                               select new RolBase { Id = "EST", Nombre = "Estudiante" }).ToList();

3.

return ResultQuery.Distinct(new RolBaseComparer()).ToList()