añadido tema oscuro, y programada la funcion de busqueda

This commit is contained in:
2024-12-21 19:16:47 -03:00
parent 990f866a71
commit 3f08dcfc81
21 changed files with 345 additions and 75 deletions

View File

@@ -7,13 +7,32 @@ namespace AlquilaFacil.Controllers;
[ApiController]
public class BusquedaController: ControllerBase {
[HttpGet("api/busqueda")]
public IActionResult FiltroPropiedades([FromHeader(Name = "Auth")]string Auth, int cantidadHabitaciones, int tipoPropiedad, [FromQuery]string servicios) {
public IActionResult FiltroPropiedades([FromHeader(Name = "Auth")]string Auth, int cantidadHabitaciones = 0, int tipoPropiedad = 0, [FromQuery]string servicios = "") {
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 3);
if (validacion1 == false) return Unauthorized();
var propiedades = RepositorioPropiedades.Singleton.ObtenerPropiedesPorHabitaciones_Tipo_Servicios();
IQueryable<PropiedadesDto>? props = null;
if (servicios == ""){
//no hay parametros de busqueda
if (cantidadHabitaciones == 0 && tipoPropiedad == 0 ) props = RepositorioPropiedades.Singleton.ListarPropiedades();
//Solo Habitaciones
if (cantidadHabitaciones != 0 && tipoPropiedad == 0) props = RepositorioPropiedades.Singleton.ObtenerPropiedesPorHabitaciones(cantidadHabitaciones);
//Solo TipoPropiedad
if (cantidadHabitaciones == 0 && tipoPropiedad != 0) props = RepositorioPropiedades.Singleton.ObtenerPropiedesPorTipo(tipoPropiedad);
//Habitaciones y TipoPropiedad
if (cantidadHabitaciones != 0 && tipoPropiedad != 0) props = RepositorioPropiedades.Singleton.ObtenerPropiedesPorHabitaciones_Tipo(cantidadHabitaciones, tipoPropiedad);
} else {
//Solo se filtra por servicios
if (cantidadHabitaciones == 0 && tipoPropiedad == 0 ) props = RepositorioPropiedades.Singleton.ObtenerPropiedesPorServicios(servicios);
//Servicios y habitaciones
if (cantidadHabitaciones != 0 && tipoPropiedad == 0) props = RepositorioPropiedades.Singleton.ObtenerPropiedesPorHabitaciones_Servicios(cantidadHabitaciones, servicios);
//Tipo y Servicios
if (cantidadHabitaciones == 0 && tipoPropiedad != 0) props = RepositorioPropiedades.Singleton.ObtenerPropiedesPorTipo_Servicios(tipoPropiedad, servicios);
// Todos los parametros
if (cantidadHabitaciones != 0 && tipoPropiedad != 0) props = RepositorioPropiedades.Singleton.ObtenerPropiedesPorHabitaciones_Tipo_Servicios(cantidadHabitaciones, tipoPropiedad, servicios);
}
return Ok(props);
}
}

View File

@@ -1,3 +1,3 @@
namespace Entidades.Dto;
public record BusquedaDto(int Id, string Ubicacion, string Servicios);
public record BusquedaDto(int Id, string Ubicacion, string? Servicios = "");

View File

@@ -5,7 +5,11 @@
<link rel="icon" type="image/png" href="/favicon.svg" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"/>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
// Configura el tema desde localStorage antes de cargar la aplicación
const savedTheme = localStorage.getItem("theme") || "light";
document.documentElement.setAttribute("data-bs-theme", savedTheme);
</script>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>AlquilaFacil</title>
</head>

View File

@@ -0,0 +1,14 @@
<!--
unicode: "fec0"
version: "3.2"
-->
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
>
<path d="M8 9a3 3 0 1 1 -3 3l.005 -.176a3 3 0 0 1 2.995 -2.824" />
<path d="M16 5a7 7 0 0 1 0 14h-8a7 7 0 0 1 0 -14zm0 2h-8a5 5 0 1 0 0 10h8a5 5 0 0 0 0 -10" />
</svg>

After

Width:  |  Height:  |  Size: 327 B

View File

@@ -0,0 +1,14 @@
<!--
unicode: "febf"
version: "3.2"
-->
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
>
<path d="M16 9a3 3 0 1 1 -3 3l.005 -.176a3 3 0 0 1 2.995 -2.824" />
<path d="M16 5a7 7 0 0 1 0 14h-8a7 7 0 0 1 0 -14zm0 2h-8a5 5 0 1 0 0 10h8a5 5 0 0 0 0 -10" />
</svg>

After

Width:  |  Height:  |  Size: 328 B

View File

@@ -2,6 +2,7 @@
import { onMount } from "svelte";
import { writable } from "svelte/store";
import { urlG } from "../stores/urlStore";
import { links, navigate } from "svelte-routing";
type Permiso = {
id: number;
@@ -38,11 +39,14 @@
console.error(e);
}
}
function redirijir(path: string){
navigate(path);
}
</script>
<div class="list-group" style="border: 1px solid black">
<div class="list-group border border-success" use:links>
{#each $permisos as item}
<a href="/accion/{item.id}" class="list-group-item list-group-item-action">
<a class="list-group-item list-group-item-action" href="/accion/{item.id}">
{item.descripcion}
</a>
{/each}

View File

@@ -29,7 +29,6 @@
}
const ret = await response.json();
localStorage.clear();
localStorage.setItem('email', ret.email);
sessionStorage.setItem('token', ret.token);
//setTimeout(() => console.log("50ms") ,50);
@@ -41,7 +40,7 @@
</script>
<Card class="position-sticky top-50 start-50 translate-middle-x" style="width: 20rem; height: auto;" theme="auto" color="dark" outline>
<Card class="position-sticky top-50 start-50 translate-middle-x border border-success" style="width: 20rem; height: auto;" theme="auto" outline>
<CardHeader>
<CardTitle>Iniciar Sesión</CardTitle>
</CardHeader>

View File

@@ -2,10 +2,12 @@
import { Navbar, NavbarBrand, NavbarToggler, Nav, Collapse } from "@sveltestrap/sveltestrap";
import { onMount } from "svelte";
import { writable } from 'svelte/store';
import { link, links } from "svelte-routing";
import './css/popup.css';
import type { Grupo } from "../types";
import { urlG } from "../stores/urlStore";
import { navigate } from "svelte-routing";
let isOpen: boolean = $state(false);
@@ -39,23 +41,39 @@
})
function redirijir(path: string){
location.replace(path);
navigate(path);
}
let theme = $state(localStorage.getItem("theme") ?? "light");
const toggleTheme = () => {
theme = theme === "light" ? "dark" : "light";
document.body.setAttribute("data-bs-theme", theme);
localStorage.setItem("theme", theme);
};
</script>
<Navbar container="xxl" expand="md" color="dark-subtle">
<NavbarBrand href="/">
AlquilaFacil
</NavbarBrand>
<div class="badge">
<div>
<div class="badge" style="background-color: turquoise;" use:links>
<a href="/Menu">
<img src="/home.svg" alt="Volver al Menú"/>
</a>
</div>
<button class="badge btn btn-outline-primary" onclick={toggleTheme} style="background-color: cadetblue;">
{#if theme === "light" }
<img src="/toggle-left.svg" alt=""/>
{:else}
<img src="/toggle-right.svg" alt=""/>
{/if}
</button>
</div>
<NavbarToggler on:click={() => (isOpen = !isOpen)} />
<Collapse isOpen={isOpen} navbar expand="md">
<Nav class="ms-auto" navbar>
<Nav class="ms-auto" navbar >
{#each $permisos as item }
<div class="dropdown">
<div class="btn-group" style="margin-left: 3px; margin-top: 3px">
@@ -63,9 +81,9 @@
<button class="btn btn-secondary dropdown-toggle dropdown-toggle-split" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<span class="visually-hidden">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu dropdown-menu-end" >
<ul class="dropdown-menu dropdown-menu-end" use:links>
{#each item.idpermisos as perm}
<a class="dropdown-item link-underline-opacity-0 link-underline" href="/accion/{perm.id}">{perm.descripcion}</a>
<a class="dropdown-item link-underline-opacity-0 link-underline" href="/accion/{perm.id}" >{perm.descripcion}</a>
<li><hr class="dropdown-divider"></li>
{/each}
</ul>

View File

@@ -1,14 +1,27 @@
<script lang="ts">
<script>
let canthabitaciones = 0;
import "./css/dotted-line.css";
import { navigate } from 'svelte-routing';
let canthabitaciones = $state(0);
let servicios = ["Gas", "Internet", "Telefono", "Luz"];
let serviciosSel = [];
let tipo = 0;
let serviciosSel = $state([]);
let tipo = $state(0);
async function formsubmit (e){
e.preventDefault();
const url = window.location.pathname;
const goto = url+"?cantidadHabitaciones="+canthabitaciones+"&tipoPropiedad="+tipo+"&servicios="+serviciosSel.join(",");
window.location.replace(goto);
}
</script>
<form class="card p-3" style="border: 1px solid black">
<form class="card p-3 border border-succes">
<p>Busqueda Filtrada</p>
<div>Busqueda Filtrada
<div class="dotted-line">
</div>
<div class="form-floating mb-3">
<input
@@ -33,6 +46,7 @@
bind:group={serviciosSel}
value={servicio}
id={`servicio-${servicio}`}
/>
<label class="form-check-label" for={`servicio-${servicio}`}>
{servicio}
@@ -53,7 +67,7 @@
<label for="idtipopropiedad">Tipo de propiedad</label>
</div>
<button type="submit" class="btn btn-primary w-100 d-flex align-items-center justify-content-center">
<button type="submit" class="btn btn-primary w-100 d-flex align-items-center justify-content-center" onclick={formsubmit}>
Buscar
<img src="/zoom.svg" alt="" class="ms-2" style="height: 1.2em;" />
</button>

View File

@@ -1,13 +1,26 @@
<script>
let {ubicacion, servicios} = $props();
<script lang="ts">
import type { PropiedadDto } from "../types";
let { prop }: { prop: PropiedadDto } = $props();
</script>
<div class="card text-center" style="border:1px solid black">
<div class="card-body">
<div class="card-img-top">
<i class="bi bi-flower3" style="font-size: 3rem;"></i>
<div class="card text-center border shadow-sm">
<div class="card-header bg-primary text-white">
<h5 class="mb-0">{prop.tipo}</h5>
</div>
<p class="card-text mt-3">{ubicacion} - {servicios}</p>
<div class="card-body">
<div class="card-img-top mb-3">
<i class="bi bi-building" style="font-size: 3rem;"></i>
</div>
<h6 class="card-title">{prop.ubicacion}</h6>
<p class="card-text">
<strong>Habitaciones:</strong> {prop.canthabitaciones}<br>
<strong>Piso:</strong> {prop.piso || "N/A"}<br>
<strong>Letra:</strong> {prop.letra || "N/A"}<br>
<strong>Servicios:</strong> {prop.servicios || "Sin servicios especificados"}
</p>
<button class="btn btn-primary">Consultar</button>
</div>
<div class="card-footer text-muted">
ID Propiedad: {prop.id}
</div>
</div>

View File

@@ -30,7 +30,7 @@
const json = await responce.json();
modalpayload = json.message;
modal = true;
location.reload();
window.location.reload();
}catch (e){
console.error(e);
}

View File

@@ -49,6 +49,6 @@
{#if $isAuthenticated}
{@render componente()}
{:else}
{navigate('/')}
{window.location.replace('/')}
{/if}
{/if}

View File

@@ -0,0 +1,5 @@
.dotted-line {
border: none;
border-top: 2px dashed #757575; /* Línea punteada de 2px de grosor y color negro */
margin: 20px 0; /* Márgenes opcionales */
}

View File

@@ -6,8 +6,11 @@
import { onMount } from "svelte";
import { fade } from "svelte/transition";
import {urlG} from "../stores/urlStore"
import type { PropiedadDto } from "../types";
let showButton = $state(false);
let propiedades: PropiedadDto[] = $state([]);
let token = sessionStorage.getItem("token");
@@ -16,18 +19,50 @@
};
onMount(() => {
checkparametros()?
busqueda():
cargaPropiedades();
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
});
function cargaPropiedades(e:Event){
e.preventDefault();
const response = fetch(String($urlG)+"/api/busqueda", {
function checkparametros(){
const params = new URLSearchParams(window.location.search);
if (params.has('cantidadHabitaciones') && params.has('tipoPropiedad')
&& params.has('servicios') ) {
return true;
}
return false
}
async function cargaPropiedades(){
const response = await fetch(String($urlG)+"/api/propiedades", {
method: "GET",
headers: {
"Auth": String(token),
}
});
if (response.ok){
propiedades = await response.json();
}
}
async function busqueda(){
const params = new URLSearchParams(window.location.search);
let hab = params.get('cantidadHabitaciones');
let tipo = params.get('tipoPropiedad');
let serv = params.get('servicios');
const response = await fetch(String($urlG)+"/api/busqueda"+"?cantidadHabitaciones="+hab+
"&tipoPropiedad="+tipo+"&servicios="+serv, {
method: "GET",
headers: {
"Auth": String(token),
}
});
if (response.ok){
propiedades = await response.json();
}
}
</script>
@@ -36,34 +71,10 @@
<div class="container mt-4">
<div class="row">
<div class="col col-md-8 order-2">
<PublicacionPropiedad ubicacion="test" servicios="test" />
<br>
<PublicacionPropiedad ubicacion="test" servicios="test" />
<br>
<PublicacionPropiedad ubicacion="test" servicios="test" />
<br>
<PublicacionPropiedad ubicacion="test" servicios="test" />
<br>
<PublicacionPropiedad ubicacion="test" servicios="test" />
<br>
<PublicacionPropiedad ubicacion="test" servicios="test" />
<br>
<PublicacionPropiedad ubicacion="test" servicios="test" />
<br>
<PublicacionPropiedad ubicacion="test" servicios="test" />
<br>
<PublicacionPropiedad ubicacion="test" servicios="test" />
<br>
<PublicacionPropiedad ubicacion="test" servicios="test" />
<br>
<PublicacionPropiedad ubicacion="test" servicios="test" />
<br>
<PublicacionPropiedad ubicacion="test" servicios="test" />
<br>
<PublicacionPropiedad ubicacion="test" servicios="test" />
<br>
<PublicacionPropiedad ubicacion="test" servicios="test" />
{#each propiedades as item}
<PublicacionPropiedad prop={item} />
<br>
{/each}
</div>
<div class="col-md-4 order-1">
<PanelBusqueda/>

View File

@@ -39,7 +39,10 @@
</script>
<NavBarAutocompletable/>
<div class="container table-responsive">
<h1 class="text-center">
Propiedades de Alta
</h1>
<div class="container table-responsive border border-success">
<table class="table-responsive table table-striped">
<thead>
<tr>

View File

@@ -39,7 +39,10 @@
</script>
<NavBarAutocompletable/>
<div class="container table-responsive">
<h1 class="text-center">
Propiedades de Baja
</h1>
<div class="container table-responsive border border-success">
<table class="table-responsive table table-striped">
<thead>
<tr>

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import Login from "../Componentes/login.svelte"
import Login from "../Componentes/LoginPanel.svelte"
import Navbar from "../Componentes/NavBarLogin.svelte";
</script>

View File

@@ -1,3 +0,0 @@
import { readable } from 'svelte/store';
export const urlG = readable('http://localhost:5007');

View File

@@ -0,0 +1,3 @@
import { readable, type Readable } from 'svelte/store';
export const urlG: Readable<string> = readable('http://localhost:5007');

View File

@@ -17,5 +17,4 @@
"moduleDetection": "force"
},
"include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"],
"references": [{ "path": "./tsconfig.node.json" }]
}

View File

@@ -11,9 +11,14 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
public IQueryable<PropiedadesDto> ListarPropiedades(){
FormattableString sqlq = $"""
SELECT p.id, p.ubicacion, p.canthabitaciones, p.piso, p.letra, tp.descripcion AS TipoPropiedad FROM Propiedades p
SELECT DISTINCT p.id, p.ubicacion, p.canthabitaciones, p.piso, p.letra, tp.descripcion AS Tipo,
GROUP_CONCAT(DISTINCT s.descripcion SEPARATOR ', ') AS Servicios
FROM Propiedades p
JOIN EstadoPropiedad ep ON p.idestado = 1
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
GROUP BY p.id
""";
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
@@ -172,8 +177,153 @@ public bool AñadirPropiedad(Propiedade? prop) {
return Guardar(con);
}
public IQueryable<BusquedaDto> ObtenerPropiedesPorHabitaciones_Tipo_Servicios(int habitaciones, int tipo, string servicios) {
public IQueryable<PropiedadesDto> ObtenerPropiedesPorHabitaciones_Tipo_Servicios(int habitaciones, int tipo, string servicios) {
string serviciosEscapados = string.Join(",", servicios.Split(',').Select(s => s.Trim()));
FormattableString sqlq = $"""
SELECT DISTINCT p.id, p.ubicacion, p.canthabitaciones, p.piso, p.letra, tp.descripcion AS Tipo,
GROUP_CONCAT(DISTINCT s.descripcion SEPARATOR ', ') AS Servicios
FROM Propiedades p
JOIN EstadoPropiedad ep ON p.idestado = 1
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
WHERE p.canthabitaciones = {habitaciones} AND p.idtipropiedad = {tipo}
AND EXISTS (
SELECT 1
FROM Servicio_Propiedad sp2
JOIN Servicios s2 ON sp2.idServicio = s2.id
WHERE sp2.idPropiedad = p.id
AND FIND_IN_SET(s2.descripcion, {serviciosEscapados})
)
GROUP BY p.id
""";
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
return ret;
}
public IQueryable<PropiedadesDto> ObtenerPropiedesPorHabitaciones_Tipo(int cantidadHabitaciones, int tipoPropiedad) {
FormattableString sqlq = $"""
SELECT DISTINCT p.id, p.ubicacion, p.canthabitaciones, p.piso, p.letra, tp.descripcion AS Tipo,
GROUP_CONCAT(DISTINCT s.descripcion SEPARATOR ', ') AS Servicios
FROM Propiedades p
JOIN EstadoPropiedad ep ON p.idestado = 1
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
WHERE p.canthabitaciones = {cantidadHabitaciones} AND p.idtipropiedad = {tipoPropiedad}
GROUP BY p.id
""";
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
return ret;
}
public IQueryable<PropiedadesDto>? ObtenerPropiedesPorServicios(string servicios) {
string serviciosEscapados = string.Join(",", servicios.Split(',').Select(s => s.Trim()));
FormattableString sqlq = $"""
SELECT DISTINCT p.id, p.ubicacion, p.canthabitaciones, p.piso, p.letra, tp.descripcion AS Tipo,
GROUP_CONCAT(DISTINCT s.descripcion SEPARATOR ', ') AS Servicios
FROM Propiedades p
JOIN EstadoPropiedad ep ON p.idestado = 1
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
WHERE EXISTS (
SELECT 1
FROM Servicio_Propiedad sp2
JOIN Servicios s2 ON sp2.idServicio = s2.id
WHERE sp2.idPropiedad = p.id
AND FIND_IN_SET(s2.descripcion, {serviciosEscapados})
)
GROUP BY p.id
""";
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
return ret;
}
public IQueryable<PropiedadesDto>? ObtenerPropiedesPorHabitaciones(int cantidadHabitaciones) {
FormattableString sqlq = $"""
SELECT DISTINCT p.id, p.ubicacion, p.canthabitaciones, p.piso, p.letra, tp.descripcion AS Tipo,
GROUP_CONCAT(DISTINCT s.descripcion SEPARATOR ', ') AS Servicios
FROM Propiedades p
JOIN EstadoPropiedad ep ON p.idestado = 1
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
WHERE p.canthabitaciones = {cantidadHabitaciones}
GROUP BY p.id
""";
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
return ret;
}
public IQueryable<PropiedadesDto>? ObtenerPropiedesPorTipo(int tipoPropiedad) {
FormattableString sqlq = $"""
SELECT DISTINCT p.id, p.ubicacion, p.canthabitaciones, p.piso, p.letra, tp.descripcion AS Tipo,
GROUP_CONCAT(DISTINCT s.descripcion SEPARATOR ', ') AS Servicios
FROM Propiedades p
JOIN EstadoPropiedad ep ON p.idestado = 1
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
WHERE p.idtipropiedad = {tipoPropiedad}
GROUP BY p.id
""";
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
return ret;
}
public IQueryable<PropiedadesDto>? ObtenerPropiedesPorHabitaciones_Servicios(int cantidadHabitaciones, string servicios) {
string serviciosEscapados = string.Join(",", servicios.Split(',').Select(s => s.Trim()));
FormattableString sqlq = $"""
SELECT DISTINCT p.id, p.ubicacion, p.canthabitaciones, p.piso, p.letra, tp.descripcion AS Tipo,
GROUP_CONCAT(DISTINCT s.descripcion SEPARATOR ', ') AS Servicios
FROM Propiedades p
JOIN EstadoPropiedad ep ON p.idestado = 1
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
WHERE p.canthabitaciones = {cantidadHabitaciones}
AND EXISTS (
SELECT 1
FROM Servicio_Propiedad sp2
JOIN Servicios s2 ON sp2.idServicio = s2.id
WHERE sp2.idPropiedad = p.id
AND FIND_IN_SET(s2.descripcion, {serviciosEscapados})
)
GROUP BY p.id
""";
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
return ret; }
public IQueryable<PropiedadesDto>? ObtenerPropiedesPorTipo_Servicios(int tipoPropiedad, string servicios) {
string serviciosEscapados = string.Join(",", servicios.Split(',').Select(s => s.Trim()));
FormattableString sqlq = $"""
SELECT DISTINCT p.id, p.ubicacion, p.canthabitaciones, p.piso, p.letra, tp.descripcion AS Tipo,
GROUP_CONCAT(DISTINCT s.descripcion SEPARATOR ', ') AS Servicios
FROM Propiedades p
JOIN EstadoPropiedad ep ON p.idestado = 1
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
WHERE p.idtipropiedad = {tipoPropiedad}
AND EXISTS (
SELECT 1
FROM Servicio_Propiedad sp2
JOIN Servicios s2 ON sp2.idServicio = s2.id
WHERE sp2.idPropiedad = p.id
AND FIND_IN_SET(s2.descripcion, {serviciosEscapados})
)
GROUP BY p.id
""";
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
return ret;
}
}