Przetłumaczenie pytania z SQL na LINQ

0

Witam czy ktoś by mi pomógł przetłumaczyć pytanie SQL na LINQ ? próbuje ogarnąć linq ale idzie mi topornie a nie ukrywam czas mi się kończy .
Pytanie

SELECT  tw_Symbol, SUM(ob_IloscMag ) as ob_IloscMag FROM vwZstWydWgKhnt 
LEFT JOIN tw__Towar ON ob_TowId = tw_Id  
LEFT JOIN sl_GrupaTw ON tw_IdGrupa = grt_Id
  WHERE dok_Status <> 2  
   AND (( (dok_DataWyst>='20180101') 
   AND (dok_DataWyst<='20181231') )  
   AND (dbo.fnMAKE_DOKPARAM(dok_Typ, dok_Podtyp) IN (720896,720897,720898))  AND (dok_MagId IN (1 , 34 )))
    AND tw_Symbol LIKE  'V%'  AND tw_Symbol LIKE'_314%' 
    AND tw_Symbol LIKE'_____________012%'
     AND( tw_Symbol LIKE '_1%'OR  tw_Symbol LIKE '_2%'OR  tw_Symbol LIKE '_3%'OR  tw_Symbol LIKE '_4%'OR  tw_Symbol LIKE '_5%'OR  tw_Symbol LIKE '_6%'OR  tw_Symbol LIKE '_7%'OR  tw_Symbol LIKE '_8%'OR  tw_Symbol LIKE '_9%') 
GROUP BY tw_Rodzaj, tw_Nazwa, tw_Symbol, tw_JednMiary, grt_Nazwa ORDER BY tw_Symbol
2

No przecież pisałem

Zdefiniuj sobie klasę
Magazyn info
public class MagazynInfo
{
public string tw_Symbol {get;set;)
public int ob_IloscMag {get;set;} // jeśli to jest int
}

i potem

var magazyny= db.Database.SqlQuery<MagazynInfo>(tu twoje zapytanie sql).ToList();

Dostaniesz listę obiektów MagazynInfo z danymi tw_Symbol, ob_IloscMag.

Nie działa?

1

Nie, bo pytasz się o zagregowane dane z Group by i wyjściem takiego zapytania nie jest obiekt klasy vwZstWydWgKhnt A taka klasę masz pewnie z ado model. Soa#1. Wczoraj musiałem czegoś podobnego użyc bo ef z Mysql nie odejmuje dayetimow.
Twoje zapytanie jest dość skomplikowane. Ono w ogóle jest poprawne?

0

Tak działa bo moje zadanie polega na utworzeniu apki na ios a ten nieszczęsny ios musi mieć api jakieś . A pytanie na pewno działa bo wykorzystuje do aplikacji desktopowej

1

No to pokaż cały kod.

0

Ale kod z aplikacji desktopowej ?

1

Kod gdzie uzywasz twgo zapytania i dokladnje jakke bledy dostajesz.

0

Chyba tutaj najbliżej byłem sukcesu ;)

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Description;
using System.Web.Mvc;
using System.Web.UI.WebControls;

using VerdentRest.Models;

namespace VerdentRest.Controllers
{
    public class vwTowarsController : ApiController
    {
        private VEREntities db = new VEREntities();

   

     
        [System.Web.Http.Route("api/getTowars2")]
        public ActionResult Index() {
            var pytanie = db.vwTowar.SqlQuery("Select tw_Symbol From vwTowar Where tw_Symbol LIKE 'V%").ToList();
            return View();
        }


        [System.Web.Http.Route("api/getTowars")]
        public IEnumerable<string> GetSymbolsStartingWithV() 
        {
            return db.vwTowar.Where(x => x.tw_Symbol.StartsWith("V")).Select(x => x.tw_Symbol ).ToList();
            
        }
  

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }

        private bool vwTowarExists(int id)
        {
            return db.vwTowar.Count(e => e.tw_Id == id) > 0;
        }
    }
}

Błąd to : Non-invocable member 'View' cannot be used like a method.
tam jest jedna metoda w linq ale bym sie nią nie sugerował ponieważ bardziej skomplikowane pytania nie da się przetłumaczyć na Linq

1

Nie możesz użyć return View() bo robisz ApiController, a w nim zasadniczo nie ma widoków.

1

Ale ten błąd nie ma nic wspólnego z zapytaniem.

Nie wiem jaki jest sens zwracać IQuerable w metodzie API ale ja się nie znam.

Jeśli te metodę masz na myśli

public ActionResult Index() {
var pytanie = db.vwTowar.SqlQuery("Select tw_Symbol From vwTowar Where tw_Symbol LIKE 'V%").ToList();
return View();
}

to nie rozumiem co tu chcesz osiągnąć bo pytasz się w sql-u o tw_Symbol i dostaniesz z takiego zapytania listę stringów więc to taką listę powinieneś zwracać a nie jakiś View()

public List<string> Index() {
            return db.vwTowar.SqlQuery("Select tw_Symbol From vwTowar Where tw_Symbol LIKE 'V%").ToList();
            
        }

albo

public HttpResponseMessage Index() {
    var symbols =  db.vwTowar.SqlQuery("Select tw_Symbol From vwTowar Where tw_Symbol LIKE 'V%").ToList();
    return Request.CreateResponse(HttpStatusCode.OK, symbols);
        
}

no i lepiej to opakować w jakiś spójny model - kilka klas, które będą wykorzystywane w komunikacji z urządzeniami.

Bardziej skomplikowane zapytania da się przetłumaczyć na linq tylko czasem nie ma sensu.

W tej metodzie też masz bałagan

public IQueryable<vwTowar> GetvwTowars()
        {
            string sqlString = "Select tw_Symbol From vwTowar Where tw_Symbol LIKE 'V%";

            var objctx = (db as IObjectContextAdapter).ObjectContext;

            ObjectQuery<vwTowar> student = objctx.CreateQuery<vwTowar>(sqlString);
            vwTowar newStudent = student.First<vwTowar>();
            return null;
        }

W zapytaniu jest "Select tw_Symbol From..." więc, znowu, dostaniesz listę stringów. Potem coś dziwnie kombinujesz i zwracasz null.
Powinno być np. coś takiego

public HttpResponseMessage GetvwTowars()
{
          string sqlString = "Select * From vwTowar Where tw_Symbol LIKE 'V%";
          var towary = db.vwTowar.SqlQuery("Select * From vwTowar Where tw_Symbol LIKE 'V%").ToList();

         return Request.CreateResponse(HttpStatusCode.OK, towary);

      
        }

Tylko, że chyba zwykle nie ma sensu zwracać całych obiektów z bazy danych (wszystkich danych) tylko to co Ci potrzeba. Lepiej przygotować sobie modele do wymiany danych w API, osobne klasy, które będą przesyłane pomiędzy telefonem a serwerem.

0

Co to tej metody

public List<string> Index() {
            return db.vwTowar.SqlQuery("Select tw_Symbol From vwTowar Where tw_Symbol LIKE 'V%").ToList();

        }

wyskakuje błąd :

Cannot implicitly convert type 'System.Collections.Generic.List<VerdentRest.Models.vwTowar>' to 'System.Collections.Generic.List<string>' >

a druga metoda bez błędu ale gdy próbuje ja sprawdzić w przeglądarce albo postman dostanie takie informacje

<Error>
<Message>
The requested resource does not support http method 'GET'.
</Message>
</Error>

To jak j a mam wywołać ? jak nie przez get-a :)
a co do mojej metody to ona była z wielu prób po prostu ja nie skasowałem później to zrobiłem ale nie zdążyłem przed tobą ;)

1

Nie sprawdzałem ale może takie coś

public List<string> Index() {
            return db.SqlQuery<string>("Select tw_Symbol From vwTowar Where tw_Symbol LIKE 'V%").ToList();

        }

Musisz dokładnie czytać i zrozumieć co się dzieje.
Takie zapytanie
return db.vwTowar.SqlQuery... zechce zwrócić listę vwTowar, tu mój błąd.
Takie: db.SqlQuery zwróci cokolwiek zechcesz i dlatego wywaliło błąd rzutowania listy verdentrest.models.vwtowar na listę stringów.

To jak j a mam wywołać ? jak nie przez get-a :)
Http ma czasowników chyba z 8. Może błąd w routingu albo daj tam [HttpGet] przed metodą.

0

ehh ja to mam pecha do tego resta ciągle coś :/ teraz coś z ToList

'object' does not contain a definition for 'ToList' and no extension method 'ToList' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?)

i nie wiem za bardzo o co chodzi . O jaki obiekt mu chodzi ? .. :/

1

Pobierz sobie taki program jak LINQPad i tam możesz sobie generować z linq na sql i na odwrót. :)

0

Tutaj są te 2 sposoby od jacek.placek :)

namespace VerdentRest.Controllers
{
    public class vwTowarsController : ApiController
    {
        private VERDENT_SPZOOEntities db = new VERDENT_SPZOOEntities();
        [System.Web.Http.Route("api/getTowars2")]
        public List<string> Index()
        {
            return db.SqlQuery<string>("Select tw_Symbol From vwTowar Where tw_Symbol LIKE 'V%").ToList();

        }
        [System.Web.Http.Route("api/getTowars2")]
        public HttpResponseMessage Index2()
        {
            var symbols = db.vwTowar.SqlQuery("Select tw_Symbol From vwTowar Where tw_Symbol LIKE 'V%' ").ToList();
            return Request.CreateResponse(HttpStatusCode.OK, symbols);
        }


        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }

        private bool vwTowarExists(int id)
        {
            return db.vwTowar.Count(e => e.tw_Id == id) > 0;
        }
    }
}

i tak jak wspominałem w ** Index** występuje problem z ToList

'object' does not contain a definition for 'ToList' and no extension method 'ToList' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?)

a Index2 nie mogę ją wywołać sprawdziłem API i widzi ja jako metodę Post :/ dziwne .

1

U mnie dział takie coś z EF 6.2, Dodaj Database po db. Nr to kolumna z numerem tekstowym. Zwraca List<string>.

var s = db.Database.SqlQuery<string>("Select Nr from Transport Where Nr LIKE '%/2018'").ToList();

Przed metodą Index2() dodaj [HttpGet] albo [AcceptVerbs("GET")]

2

W Index2 masz taki sam Route jak w w Index ("api/getTowars2"), więc jak wejdziesz na http://example.com/api/getTowars2 to które powinno się odpalić?

0

Działą :D Dziękuję za pomoc jacek.placek (Jak kiedyś się spotkamy realu to stawiam ci piwo ;) ) również Ktos też dzięki również tez pomogłeś

Tutaj jest rozwiązanie moze się komuś przyda :

       [System.Web.Http.HttpGet]
        public List<double> Index()
        {
          return  db.Database.SqlQuery<double>("SELECT zmiena FROM tabelka ").ToList(); ;

        } 

Ale jeszcze mam pytanko po 1 gdy chce aby pytanie zwróciło więcej niż jedną zmienia ? bo mi wskakuje z tego powodu błąd

System.Data.Entity.Core.EntityCommandExecutionException: 'The data reader has more than one field. Multiple fields are not valid for EDM primitive or enumeration types.'

i 2 pytanko chyba najważniejsze nie można jakoś podać adresu ?
to znacz jak wcześniej miałem [System.Web.Http.Route("api/getTowars3")] no mogłem ustalic adres a tutaj nie wiem jak i czy w ogólne mogę .

1

To dobrze, że w końcu się udało :)
jak chcesz kilka zmiennych (kolumn) to, jak pisałem wcześniej, musisz zdefiniować sobie jakąś klasę, która będzie przechowywać te wartości.

public class DataModel
{
    public string zmianna1 {get;set;}
    public string zmianna2 {get;set;}
}

i zapytanie

var res = db.Database.SqlQuery<DataModel>("SELECT coś1 as zmienna1, cos2 as zmianna2 FROM tabelka ").ToList(); 

Nie testowałem ale coś takiego powinno zadziałać. Powinno zwrócić List<DataModel>.

0

**AKTUALIZACJA ROZWIĄZANIA :) **
Modyfikacje zaproponowane przez jacek.placek i moje dodaja takie funkcjie :

  • Wyświetlenia więcej niż jedną zmienią
  • Dodanie możliwości ustaleniu adresu
  • Możliwość dodania wstawienia danych (zmiena a i b )
    **UWAGA ** Używamy POST nie GET (nie wiem czemu )
    Przykładowy adres do wpisania :

http://localhost:50398/api/getTowars3?a=V&b=314

  public class DataModel
        {
            public string symbol { get; set; }
            public string nazwa { get; set; }
        }

        [System.Web.Http.Route("api/getTowars3")]
        [ResponseType(typeof(vwTowar))]
        public List<DataModel> Index(string a, string b)
        {
            return db.Database.SqlQuery<DataModel>("SELECT xxx as symbol , zzz as nazwa FROM tabelka WHERE xxxx LIKE ' "+a+b+"'  ").ToList(); ;
        }

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