Pobranie danych za pomocą Linq w relacji wiele do wiele

0

Próbuje pobrać określone pokoje, który nie są zarezerwowany (w tym przypadku określam na podstawię daty, czy nie są zarezerwowane). Niestety nie bardzo potrafię odnależć się w relacji wiele do wiele. Jak nalezy skonstruować zapytanie Linq?

public ActionResult ZnajdzWolnePokoje(int _TypPokoju, DateTime _DataZameldowania, DateTime DataWymeldowania)
{
    var wolnePokoje = db.PokojRezerwacja.Where(r=>r.Pokoj.TypPokoju == _TypPokoju
    && r.DataZameldowania!=_DataZameldowania
    && r.DataWymeldowania!= DataWymeldowania);

    return View(wolnePokoje);
}
class TypPokoju
{
     public int ID{get;set;}
     public int? TypPokoju{get;set;}
     public string Opis{get;set;}
}
class Pokoj
{
      public int ID{get;set;}
      publc string Status{get;set;}
}

class PokojRezerwacja
{
       public int RezerwacjaID{get;set;}
       public int PokojID{get;set;}
      public DateTime DataZameldowania{get;set;}
      public DateTime DataWymeldowania{get;set;}
}

class Rezerwacja
{
      public int ID{get;set;}
      
}

0

A typ pokoju ma jakieś powiązanie, z którąkolwiek z klas? Z zapytania widać, że ma, ale przez jaką właściwość. Mógłbyś wrzucić info o kluczach, bo tak to trzeba się wszystkiego domyślać, najlepiej w takim formacie:

PokojRezerwacja.PokojID <--> Pokoj.ID

Warunek będzie coś w ten deseń:

r=>r.Pokoj.TypPokoju == _TypPokoju && (((DataZameldowania < r.DataZameldowania) && (DataWymeldowania < r.DataZameldowania)) || (DataZameldowania > r.DataWymeldowania))

No i chciałbym zauważyć, że nie masz problemu ze skonstruowaniem zapytania Linq, a z ułożeniem odpowiedniego warunku do tego zapytania

0

Relacje pomiędzy poszczególnymi tabelami. Dodałem tym razem wszystkie informacje (np. tabela platnosc, uzytkownik)
TypPokoju 1:N Pokoj
Pokoj 1:N PokojRezerwacja
Rezerwacja 1:N PokojRezerwacja
Rezerwacja 1:1 Platnosc
Uzytkownik 1;N Rezerwacja

0

Model trzeba najpierw dopracować. To, ze masz w TypPokoju pole PokojId nie oznacza jeszcze żadnego powiązania. To samo w tabeli PokojRezerwacja. Zobacz w bazie danych czy Ci sie wygenerowały klucze obce.

Poza tym szczegół logiczny czy domenowy. Data zameldowania czy wymeldowania ma się nijak do rezerwacji. To kwestia logicznych nazw, ale zwracaj na takie rzeczy uwagę bo w większych aplikacjach może być duże zamieszanie przez takie nazwy. Lepiej dać RezerwacjaOd i Do albo coś podobnego.

public class TypPokoju
{
     public int ID{get;set;}
     
     public string Opis{get;set;}
    public virtual ICollection<Pokoj> Pokoje { get; set; }
}
public class Pokoj
{
      public int ID{get;set;}
      publc string Status{get;set;}
    
    public int? TypPokoju{get;set;} // konfiguracja klucza obcego albo tu w Annotiation albo we FluentAPI
    public virtual TypPokoju Typ { get; set; }

    public ICollection <PokojRezerwacja> PokojRezerwacje {get;set;}
}
 
public class PokojRezerwacja
{
       public int RezerwacjaID{get;set;} // to trzeba skonfigurować jako klucz
       public int PokojID{get;set;} // // to trzeba skonfigurować jako klucz np

/*
    [Key, Column(Order = 0)]
    public int RezerwacjaID{get;set;}
    [Key, Column(Order = 1)]
    public int PokojID{get;set;}
*/

    public virtual Pokoj Pokoj {get;set;}
    public virtual rezerwacja Rezerwacja{get;set;}

      public DateTime DataZameldowania{get;set;}
      public DateTime DataWymeldowania{get;set;}
}

public class Rezerwacja
{
      public int ID{get;set;}
     public ICollection <PokojRezerwacja> PokojRezerwacje {get;set;}
}

i dopiero teraz. Jak chcesz się dowiedzieć, które pokoje są wolne to tabela PokojRezerwacja Ci na to nie odpowie bo tam nie ma tych informacji, tam są tylko pokoje, które są zarezerwowane. Musisz się pytać o dane z tabeli Pokoje w powiązaniu z PokojRezerwacje.

Np.

db.Pokoje.Where(x => x.PokojRezerwacje.Count(z => z.DataZameldowania >= d1 ) == 0);

albo z Any

db.Pokoje.Where(x => !x.PokojRezerwacje.Any(z => z.DataZameldowania >= d1 ));

Tu sprawdzam tylko DataZameldowania bo jak pokój ma być wolny od tej daty to DataWymeldowania już mnie nie interesuje bo ten pokój i tak jest zajęty od DataZameldowania.

0

@jacek.placek: Ten pojedynczy warunek z datą nie wystarczy tylko musi być taki jak ja napisałem, a dlaczego?
(chociaż ten fragment szło by wywalić (DataZameldowania < r.DataZameldowania))

Przykład:

Dziś mamy 19.11.2017
Pokój jest zarezerwowany na dzień 25.11.2017 - nieistotne (informacja w bazie danych)
więc ktoś może go jeszcze zarezerwować na: 20.11.2017 - 23.11.2017
więc obie informacje o dacie są istotne.

Co do Ciebie WalkaTrwa to wiesz co to są klucze primary key, foreign key? Mi chodziło jakie są powiązania między kolumnami tabel w bazie danych.

0

Chciałem po prostu znależć wszystkie dostępne pokoje w określonym terminie. Nazwy kiepskie, bo sie ucze dopiero. Dzięki za pomoc.

0

Bardzo dobrze. Nikt nie urodził się z taką wiedzą, wszyscy cały czas się uczą. Nawet jeśli jakaś odpowiedź wydaje Ci niefajna to się nie przejmuj. Zwykle nie chodzi o to żeby komuś coś udowadniać tylko ludzie piszą szybko, skrótami.
Linq jest sporym narzędziem. Pooglądać przykłady.
Nie idź na skróty w myśleniu czy analizie. Nawet doświadczeni developerzy wpadają we własne kalki i kopiują swoje wcześniejsze podobne rozwiązania bez zastanowienia.
Takie rzeczy jak nazwy, metod, zmiennych, klas mają znaczenie bo programują podświadomie Twój mózg.

Model to podstawa. Nie myśl o modelu jak o bazie danych tylko o zachowaniu obiektow i danych dla tych zachowań. Co robią obiekty, jak się zmieniają a na końcu być może z czego są zbudowane. Bazę zostaw na koniec. Nie rób UI przed testami. Testy mogą być pierwszym UI. Trudne ale się opłaci.

0

Co w przypadku jak szukam wolnych pokojów po dacie, natomiast jeszcze żaden pokój nigdy nie był zarezerwowany?
Informacje o dacie zameldowania, wymeldowania mam w tabeli pośredniej. Być może lepiej było by zrobić Rezerwacja jest 1:N z Pokoj i w tabeli Rezerwacja dać informacje data_zam, data_wym ?

0

No to bierzesz tabelę pokoj i łączysz ją z tabelą pokojRezerwacja za pomocą left join. Wtedy będziesz miał listę wszystkich pokoi, a te które nie były jeszcze rezerwowane to w kolumnie data będą miały null więc ułożysz odpowiedni warunek i będzie trybiło. Jak zrobić lewego joina przy użyciu LINQ to musisz poszukać na angielskich internetach, bo nie mam pojęcia, ale na pewno się da.

0

Zapytanie linq z mojego wcześniejszego posta to obsłuży o czym piszesz tylko trzeba warunki z datami poprawić zgodnie z tym co pisał @Manuel.Artificer.
Czegoś w nich nie rozumiesz?

0

Hmm udało mi się dzięki wam zrobić wyszukiwanie pokojów według kryteriów. Wygląda to tak, że mam ilość osob, data_od,data_do i znajduję mi pokoje. Czyli wyświetla mi 10 pokojów i mam koło nich przycisk rezerwuj. Teraz się zastanawiam jak zrobić, by użytkownik miał możliwość rezerwacji wielu pokojów. (Po to własnie mam relacje wiele do wiele między pokoj, rezerwacja). Po kliknięciu przekierowuję mnie do widoku, który określa ile jest do zaplaty. Chodzi o to, że na jednym RezerwacjaID będę mieć odniesienie do paru pokojów. Chociaż tak się zastanawiam, czy nie lepsze było by zrobienie relacji Jeden do wiele między pokój a rezerwacja. Co sądzicie?

0

Wiele do wielu jest niepotrzebne jeśli chodzi tylko o kilka pokoi w rezerwacji, ale jest potrzebne jeśli nie chcesz tracić informacji o wcześniejszych rezerwacjach chyba, ze jakoś inaczej to obsłużysz.
W 1..n masz pokoje przypisane do rezerwacji. Jeśli przypiszesz pokój do innej (kolejnej, np. w przyszłym miesiącu) rezerwacji to pokój odłączy się z wcześniejszej rezerwacji i przypisz do następnej bo pokój ma jedną rezerwację a rezerwacja ma wiele pokoi. Więc konieczny jest n..n. Chyba, ze inaczej zupełnie to zamodelujesz. Bardziej w stylu DDD gdzie Pokój w sensie zasobu (Room) jest innym obiektem niż pokój w Rezerwacji (ReservedRoom) ale to już naprawdę trzeba wiedzieć co się robi.
Więc (wiem, nie zaczyna się zdania od więc) w prostszym przypadku n..n bo rezerwacja może mieć kilka pokoi i jednocześnie ten sam pokój może należeć do kilku rezerwacji.
A jeśli chodzi o dodawanie kilku pokoi do rezerwacji to można to zrobić podobnie jak typowy koszyk w sklepach internetowych. Dodajesz pokój do rezerwacji i zapamiętujesz to gdzieś (sesja, baza...). Po dodaniu jednego pokoju pokazujesz wolne pokoje (uwzględniając ten zarezerwowany przed chwilą) i klient może sobie dodać kolejny pokój. Jak towary w koszyku.
Na koniec klient potwierdza całą rezerwacje i wtedy ostatecznie, że chce dokonać rezerwacji wszystkich dodanych pokoi.
Ale...
Konieczne jest wprowadzenie odpowiednich zabezpieczeń jeden klient może sobie dodać do rezerwacji pokoje i ich ostatecznie nie potwierdzić i wtedy coś trzeba z tym zrobić. jakoś je anulować. Dodatkowo inny klient może w tym samym czasie dodać te same pokoje (o ile aplikacja mu pozwoli, a w sumie powinna pozwolić do momentu zatwierdzenia rezerwacji bo pierwszy klient może nie zatwierdzić rezerwacji) i wtedy ostateczne sprawdzenie stanu wolnych pokoi powinno się odbywać w momencie zatwierdzenia całej rezerwacji, a najlepiej po płatności :). Jak widać im dalej w las tym więcej drzew.
Albo jakiś mechanizm potwierdzenia rezerwacji przez pracownika hotelu i mail z potwierdzeniem lub anulowaniem do klienta.

0

Zaimplementowałem koszyk z tego: https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions/mvc-music-store/mvc-music-store-part-8
Normalnie dodaje do koszyka, sumuje cene ale nie usuwa. Metoda odpowiedzialna za wywolanie akcji kontrolera ShoppingCart to:

<script type="text/javascript">
    $(function () {
        // Document.ready -> link up remove event handler
        $(".RemoveLink").click(function () {
            // Get the id from the link
            var recordToDelete = $(this).attr("data-id");
            if (recordToDelete != '') {
                // Perform the ajax post
                $.post("/ShoppingCart/RemoveFromCart", {"id": recordToDelete },
                    function (data) {
                        // Successful requests get here
                        // Update the page elements
                        if (data.ItemCount == 0) {
                            $('#row-' + data.DeleteId).fadeOut('slow');
                        } else {
                            $('#item-count-' + data.DeleteId).text(data.ItemCount);
                        }
                        $('#cart-total').text(data.CartTotal);
                        $('#update-message').text(data.Message);
                        $('#cart-status').text('Cart (' + data.CartCount + ')');
                    });
            }
        });
    });
</script>

Po ustawieniu breakow na metode RemoveFromCart kontrolera ShoppingCart~ zauważyłem, że wgl nie zostaje wywolana ta akcja. Jak klikam na stronie usun element z koszyka to wtedy dostaje w url jedynie # i nic wiecej. Tak jakby id nie przekazywało w url. Usuwanie jest w tym poradniku zrobione przy użyciu ajaxa i wygląda jakby to ajax wlaśnie mi nie działał. Czy orientuję się ktoś na czym może polegać problem?

0

Poradziłem sobie, import którego użyłem byl za stary. Teraz po prostu renderuje scripty za pomoca bundla.

1 użytkowników online, w tym zalogowanych: 0, gości: 1