Как написать это заявление C # в linq - PullRequest
0 голосов
/ 09 апреля 2019

Я пытаюсь получить связанные таблицы Adress и PlzOrt в объекте User.Отношения таковы:

Пользователь 1: 1 Адрес

Адрес n: 1 PlzOrt

Объекты, помеченные из БД

public partial class User
{
    //No hash sets for Adress Scaffolded (probably unnecessary since the is 
    //only ever one address per user

    public int IdUser { get; set; }
    public int? FidAdresse { get; set; }
    public string Email { get; set; }
    public string Vorname { get; set; }
    public string Nachmname { get; set; }

    [ForeignKey("FidAdresse")]
    [InverseProperty("User")]
    public virtual Adresse FidAdresseNavigation { get; set; }
}

public partial class Adresse
{
    public Adresse()
    {
        User = new HashSet<User>();
    }

    public int IdAdresse { get; set; }
    public int FidPlzOrt { get; set; }
    public string Strasse { get; set; }
    public string Hausnr { get; set; }

    [ForeignKey("FidPlzOrt")]
    [InverseProperty("Adresse")]
    public virtual PlzOrt FidPlzOrtNavigation { get; set; }
    [InverseProperty("FidAdresseNavigation")]
    public virtual ICollection<User> User { get; set; }
}

public partial class PlzOrt
{
    public PlzOrt()
    {
        Adresse = new HashSet<Adresse>();
    }

    public int IdPlzOrt { get; set; }
    public string Plz { get; set; }
    public string Ort { get; set; }

    [InverseProperty("FidPlzOrtNavigation")]
    public virtual ICollection<Adresse> Adresse { get; set; }
}

Вот linq, который не работает.

return _context.User
            .Include(u => u.FidPermissionNavigation)
            .Include(c => c.FidAdresseNavigation)
                .ThenInclude(c => c.FidPlzOrtNavigation)
            .FirstOrDefault(c => c.IdUser == id);

Линк работает, когда я не включаю инструкцию "ThenInclude (c => c.FidPlzOrtNavigation)", но я хочу эту информацию в своем объекте.

Вот C #, который дает мне ожидаемые результаты:

 public User GetUser(int id)
    {

        foreach (User user in _context.User)
        {
            if (user.IdUser == id)
            {
                foreach (Adresse adresse in _context.Adresse)
                {
                    if (adresse.IdAdresse == user.FidAdresse)
                    {
                        user.FidAdresseNavigation = adresse;

                        foreach (PlzOrt plzOrt in _context.PlzOrt)
                        {
                            if (plzOrt.IdPlzOrt == adresse.FidPlzOrt)
                            {
                                user.FidAdresseNavigation.FidPlzOrtNavigation = plzOrt;
                                break;
                            }
                        }

                        break;
                    }
                }

                return user;
            }
        }

        return null;
 }

Перевод этого оператора linq был бы очень полезен.Заранее спасибо.

Сгенерированный код db_context на случай, если вам это интересно или это поможет

modelBuilder.Entity<User>(entity =>
        {
            entity.HasKey(e => e.IdUser)
                .HasName("PRIMARY");

            entity.HasIndex(e => e.FidAdresse)
                .HasName("fk_User_Adresse1_idx");

            entity.HasOne(d => d.FidAdresseNavigation)
                .WithMany(p => p.User)
                .HasForeignKey(d => d.FidAdresse)
                .HasConstraintName("fk_User_Adresse1");
        });

modelBuilder.Entity<Adresse>(entity =>
        {
            entity.HasKey(e => e.IdAdresse)
                .HasName("PRIMARY");

            entity.HasIndex(e => e.FidPlzOrt)
                .HasName("fk_Adresse_plz_ort1_idx");

            entity.HasOne(d => d.FidPlzOrtNavigation)
                .WithMany(p => p.Adresse)
                .HasForeignKey(d => d.FidPlzOrt)
                .OnDelete(DeleteBehavior.ClientSetNull)
                .HasConstraintName("fk_Adresse_plz_ort1");
        });

modelBuilder.Entity<PlzOrt>(entity =>
        {
            entity.HasKey(e => e.IdPlzOrt)
                .HasName("PRIMARY");
        });

1 Ответ

1 голос
/ 10 апреля 2019

Итак, у вас есть id, и вы хотите, чтобы единственный пользователь, имеющий этот идентификатор в качестве первичного ключа, вместе со своим адресом и своим PlzOrt.

Всякий раз, когда вы запрашиваете, используйте Выбрать, чтобы получить данные. Используйте Включить, только если вы хотите обновить извлеченные данные.

Причина выбора в том, что у вас больше свободы в выборе. Кроме того, вы можете ограничить извлекаемые данные: если вы запрашиваете у школ своих учеников, вы знаете, что у каждого ученика школы 10 будет внешний ключ SchoolId, равный 10. Так зачем извлекать этот внешний ключ для каждого из учеников школы 1000?

Я не знаком с возможностями ef-core. Знает ли он, что если вы выберете одно из виртуальных свойств, для которого необходимо (групповое) соединение? В этом случае проще использовать Select.

Если вам придется делать свои объединения самостоятельно:

var requestedUserWithAddresAndPlz = dbContext.Users.

    // keep only the user with id
    .Where(user => user.IdUser == id)

    // every User has exactly one Address: use a normal join
    .Join(dbContext.Addresses,
    user => user.IdUser,              // from every User take IdUser
    address => addres.IdAddress,      // from every Address take IdAddress

    // result selector: take the user with its address to make one new
    (user, address) => new
    {
        // Select only the User properties you plan to use
        Id = user.IdUser,
        Name = user.Name,
        ...

        Address = new
        {
            // again: select only the properties you plan to use
            // no need to select IdAddress, you know the value!
            Street = address.Street,
            HouseNumber = address.HouseNumber,

            // to fetch the Plz: fetch the one-and-only PlzOrt with address.FidPlzOrt
            Plz = dbContext.PlzOrts
                  .Where(plzOrt => plzOrt.PlzOrdIt == address.FidPlzOrt)
                  .FirstOrDefault(),
    })
    .FirstOrDefault();

Примечание. Я использовал анонимные типы для большей свободы выбора только тех свойств, которые я планирую использовать. Я также могу дать своим свойствам имена, которые я хочу.

Недостаток: вы не можете использовать анонимные типы в качестве возвращаемых значений. Если вам действительно нужно это за пределами вашей функции, используйте создать класс, содержащий ваши данные, и используйте новый SomeClass (). Преимущество: если ваша база данных изменяется, SomeClass не нужно менять, и поэтому ваши абоненты не заметят изменения в вашей базе данных.

...