31 messaggi dal 03 aprile 2014
Salve ragazzi, dopo anni di php e laravel per motivi lavorativi sto passando a .net core.

ho iniziato a leggere qualcosa dal sito microsoft.

ma adesso ho un piccolo problema che non riesco a risolvere.

provenendo da laravel, per la gestione del model, bastava crearlo da pannello di comandi e me lo ritrovavo sul controller per interrogarlo.

Vorrei fare la stessa cosa con EFcore ma non capisco come fare, sul sito ufficiale si parla di Models ma subito dopo mi costringe a fare lo Scaffolding, cosa che a me non interessa minimamente.

in breve creato il Model Magazzino, Come faccio a richiamarlo da HomeController?

Thanks
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,

in breve creato il Model Magazzino,


Ok, quindi hai la tua classe Magazzino e l'hai mappata nel tuo DbContext più o meno così:
public class MyContext : DbContext
{

    public MyContext(DbContextOptions<MyContext> options)
        : base(options)
    {
    }

    public virtual DbSet<Magazzino> Magazzini { get; set; }


    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Magazzino>().ToTable("Magazzini");
    }
}


Ora devi registrare il DbContext nel metodo ConfigureServices della classe Startup.
services.AddDbContext<MyContext>();


A questo punto lo puoi ricevere nel costruttore dell'HomeController grazie al meccanismo di dependency injection di ASP.NET Core.
public class HomeController : Controller {
  private readonly MyContext context;
  public HomeController(MyContext context) {
    this.context = context;
  }

  public async Task<IActionResult> Index() {
     //Qui usa LINQ per interrogare Magazzini
     var magazziniDiRoma = await context.Magazzini.Where(magazzino => magazzino.Citta == "Roma").ToListAsync();

     //Qui fai qualcosa con gli oggetti che hai ottenuto...
     //E poi restituisci la View
     return View();
  }
}


In alternativa al costruttore, lo puoi ricevere come parametro dell'action, purché usi l'attributo [FromServices]
public class HomeController : Controller {

  public async Task<IActionResult> Index([FromServices] MyContext context) {
     //Qui usa LINQ per interrogare Magazzini
     var magazziniDiRoma = await context.Magazzini.Where(magazzino => magazzino.Citta == "Roma").ToListAsync();

     //Qui fai qualcosa con gli oggetti che hai ottenuto...
     //E poi restituisci la View
     return View();
  }
}



bastava crearlo da pannello di comandi e me lo ritrovavo sul controller per interrogarlo.

Beh, questo è considerabile "scaffolding"... come mai dici che non ti interessa fare la stessa cosa con Entity Framework Core?

ciao,
Moreno
Modificato da BrightSoul il 03 ottobre 2018 19.36 -

Enjoy learning and just keep making
31 messaggi dal 03 aprile 2014
intanto grazie per la tua risposta.

perchè fino ad oggi intendevo lo scaffolding dove visualstudio mi creava le view per l'edit, create etc..

ora ho scoperto lo scaffolding per la creazione dei model e dei context per ogni tabella.
però continuo a non capirci niente.

quindi se devo usare due tabelle all'interno di un controller

 private readonly MyContext context;
  public HomeController(MyContext context) {
    this.context = context;
  } 

private readonly MyContext2 context2;
  public HomeController(MyContext2 context2) {
    this.context2 = context2;
  }


tutto sto casino per ogni model????

Comunque non sò come ho fatto ma ho caricato tutto su cartella data, dentro ho inserito un nomeprogettoContext.cs ed all'interno ho scritto

 public DbSet<xxx.Models.PlanimetriaMagazzini> PlanimetriaMagazzini { get; set; }
        public DbSet<xxxx.Models.Magazzini> Magazzini { get; set; }


E quindi nel Controller mi richiamo il file context e posso utilizzare le tabelle senza scrivere quanto fatto soprà, però se ho più key in un model, non posso scrivere [key]chiave1 [key]chiave2 ma devo usare le API fluent....mha!!!!!

poi quando cerco su google join con EFcore, alcuni mi fanno usare .Join invece sul sito ufficiale mi fà usare include e theninclude....e in tutto questo continuo a non capirci niente.

poi tu mi parli di LINQ, ma perdonami ma EFCORE non dovrebbe sostituire LINQ??
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao, prego.


però continuo a non capirci niente.

Questo è normale e succede perché stai affrontando troppi argomenti contemporaneamente. Devi organizzare il tuo studio procedendo poco alla volta, in maniera strutturata e prendendoti del tempo per digerire bene ogni cosa. Meglio ancora sarebbe se ti procurassi un libro o se ti affiancassi a una persona già esperta in ASP.NET Core.

L'acqua della piscina è piacevole se ci entri gradualmente. Se invece ti tuffi a bomba da un trampolino di 10 metri avrà la consistenza del granito.
Detto questo, cercherò di aiutarti come posso a sbrogliare la matassa.


quindi se devo usare due tabelle all'interno di un controller
tutto sto casino per ogni model????

Ovviamente no perché ogni DbContext può accogliere più di un DbSet (quanti ne vuoi), che sono il tuo punto di ingresso per interrogare il modello concettuale.

public DbSet<xxx.Models.PlanimetriaMagazzini> PlanimetriaMagazzini { get; set; }
public DbSet<xxxx.Models.Magazzini> Magazzini { get; set; }

Questo è corretto, hai creato 2 DbSet nello stesso DbContext e questo ti permetterà di interrogare sia l'entity set PlanimetriaMagazzini che Magazzini. Ti consiglio questo:

Rinomina le classi di entità al singolare, perché ciascuna di esse rappresenta un singolo oggetto. Quindi Magazzini rinominala in Magazzino, mentre PlanimetriaMagazzini rinominala PlanimetriaMagazzino. Puoi rinominare facilmente facendo tasto destro sul nome -> Rinomina (o tasto F2). In alternativa puoi anche andare a rinominare direttamente il file Magazzini.cs: Visual Studio ti chiederà se vuoi cambiare anche il nome della classe. Tu accetta.

I nomi delle proprietà di tipo DbSet invece vanno bene così perché rappresentano degli insiemi. Quindi il codice rivisto sarà così:
public DbSet<PlanimetriaMagazzino> PlanimetriaMagazzini { get; set; }
public DbSet<Magazzino> Magazzini { get; set; }

Come vedi ho tolto anche xxx.Models perché non vale la pena ripeterlo ogni volta dato che puoi aggiungere uno using xxx.Models; in cima al file .cs.


E quindi nel Controller mi richiamo il file context e posso utilizzare le tabelle senza scrivere quanto fatto soprà,

MyContext e MyContext2 eliminali, dato che ormai stai lavorando con nomeprogettoContext.


però se ho più key in un model, non posso scrivere [key]chiave1 [key]chiave2 ma devo usare le API fluent....mha!!!!!

EFCore è un prodotto ancora giovane e non ha ancora questa funzionalità. C'è una issue aperta su GitHub a riguardo, sintomo che il problema è noto e che prossimamente verrà lavorato dal team di sviluppo.

A prescindere da questo, io ti consiglio di usare sempre la fluent API per due motivi:
  • Come hai avuto modo di notare, offre più funzionalità rispetto agli attibuti;
  • Ti permette di centralizzare la logica di mapping, che altrimenti sarebbe sparsa in giro per il progetto (ma è questione di gusti);
  • Ti permette di mantenere le tue classi di entità realmente agnostiche sul come verranno persistite e questo, come leggi qui, è una cosa che ha senso fare anche in PHP.



poi quando cerco su google join con EFcore, alcuni mi fanno usare .Join invece sul sito ufficiale mi fà usare include e theninclude....e in tutto questo continuo a non capirci niente.

Join non si usa perché con EFCore, così come con gli ORM del PHP, si possono mappare relazioni tra entità ed accedervi tramite proprietà di navigazione. Leggi qui:
https://www.learnentityframeworkcore.com/configuration/one-to-many-relationship-configuration
Per "proprietà di navigazione" si intende una proprietà che ti permette da un lato all'altro della relazione. Nella pagina qui sopra vedi appunto l'esempio di una relazione tra Company e Employee (una Company ha molti Employee).
Se hai tra le manu un oggetto di tipo Company e vuoi conoscere quali Employee lavorano per essa, ti basterà scrivere, così, senza usare alcuna Join.
var employees = company.Employees;


Nel momento in cui accedi alla proprietà Employees, EFCore interviene dietro le quinte e invia una query SQL al database per recuperare gli Employee. Questo può essere un problema, specialmente se nel database hai 1000 Company e le cicli con un foreach per estrarre gli Employee da ciascuna di esse. Se hai abilitato il lazy loading e senza che tu ne sia realmente consapevole, EFCore sta inviando 1000 query distinte al database, una per ogni lista di Employee che stai ciclando, facendoti pagare 1000 volte il seppur piccolo overhead che deriva dall'inviare una query al database. Questo è noto come problema "Select N+1" e riguarda tutti gli ORM in tutti i linguaggi.

Quindi, se già sai a propri che andrai e leggere quegli Employee, puoi manifestare questa tua intenzione a EFCore con il metodo Include, in modo da recuperare tutti i dati delle entità relazionate con una sola query, che è decisamente più efficiente di inviarne 1000. Questo è noto come "eager loading" che penso tu conosca dato che avrai sicuramente usato Doctrine e/o Eloquent.


poi tu mi parli di LINQ, ma perdonami ma EFCORE non dovrebbe sostituire LINQ??

LINQ è l'insieme degli extension method che ti permettono di interrogare il modello concettuale. Quando usi i metodi Where, OrderBy, Select, ecc.. stai usando LINQ. In questo caso LINQ sta agendo sugli insiemi esposti dal DbContext per mezzo dei DbSet ma LINQ è una funzionalità del linguaggio C# che puoi usare per interrogare collezioni di oggetti in memoria, su file XML, su DataSet e da una serie di altre fonti.

Quindi, LINQ è uno strumento di interrogazione, non è una tecnologia di accesso ai dati.
Quello che forse intendi tu è "Linq To Sql" che è un progenitore di Entity Framework e che nessuno usa più da 10 anni.

Se hai altre domande scrivi qui, non lasciare che la frustrazione influenzi la tua opinione su ASP.NET Core.
ciao,
Moreno

Enjoy learning and just keep making
31 messaggi dal 03 aprile 2014
sempre grazie per le tue risposte.

altra cosuccia non chiara, ritornando al DB, quando faccio lo scaffolding della singola tabella, posso chiedere di generare un file Context che per me è molto comodo, perchè da quanto ho visto mi gestisce tutte le condizioni della tabella compresa le key etc.
il mio problema è che non riesco ad utilizzarli, perchè nel controller posso chiamarmi un solo Context


Ora quello che faccio io è questo.
Inserisco su "mioprogettoContext"
public DbSet<xxx.Models.PlanimetriaMagazzini> PlanimetriaMagazzini { get; set; }
public DbSet<xxxx.Models.Magazzini> Magazzini { get; set; }


E poi per risolvere il problema delle doppie key scrivo sempre nello stesso file quanto segue,
 
modelBuilder.Entity<PlanimetriaMagazzini>()
                .HasKey(c => new { c.Dbgruppo, c.CodMag });


cioè vado ad eliminare il file Context che mi genera nello scaffolding.

IN BREVE:mi piacerebbe conoscere il modo migliore per utilizzare i Context generati, perchè sono molto comodi e completi...
spero di essere stato chiaro
;-)
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao, grazie!
Diciamo che lo scaffolding è un'operazione che di solito fai una volta a inizio progetto. Per questo, il tool non permette di integrare un DbContext esistente. Ho provato con questo comando (l'esempio è per Sqlite):
dotnet ef dbcontext scaffold "Data Source=Data/Database.db" Microsoft.EntityFrameworkCore.Sqlite --context-dir Services/Data/ --context MyDbContext --table NomeTabella

Però, se già esiste un file /Services/Data/MyDbContext.cs, allora il comando fallirà con questo errore:
The following file(s) already exist in directory C:\Users\User\Desktop\progetto\: Services\Data\MyDbContext.cs. Use the Force flag to overwrite these files.

NON usare la Force flag perché il dbContext originale verrebbe sovrascritto, facendoti perdere del codice.

Se vuoi fare lo scaffolding poco a poco ti conviene crearti un nuovo DbContext e portare i le parti interessanti nel DbContext che hai già. Poi elimini quel DbContext di comodo che ti eri creato.

ciao,
Moreno

Enjoy learning and just keep making
31 messaggi dal 03 aprile 2014
ah, quindi un singolo Context deve contenere le regole di tutte le tabelle.
noi purtroppo non possiamo fare lo scaffolding di tutte le tabelle, perchè quando all'apertura di visual studio, posso dire ciao ciao al mio computer, penso causato dal numero enorme di model che ha generato.

quindi se ho capito bene, qui devo inserire tutte le regole che impone ogni singola tabella?
perchè io fino ad oggi ho inserito solo le regole delle key
  protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<PlanimetriaMagazzini>()
                .HasKey(c => new { c.Dbgruppo, c.CodMag });
            modelBuilder.Entity<Magazzini>()
              .HasKey(c => new { c.Dbgruppo, c.CodMag });


E poi a seguire

   public DbSet<xxxxx.Models.PlanimetriaMagazzini> PlanimetriaMagazzini { get; set; }
        public DbSet<xxxxx.Models.Magazzini> Magazzini { get; set; }

p.s. ancora devo fare le modifiche che mi avevi consigliato.


però a me piaceva l'idea di utilizzare un singolo Context per ogni tabella, perchè tutto su un file diventa lunghissimo e confusionario secondo me, mi riferisco alla regole delle tabelle, come lunghezza stringa etc.
11.886 messaggi dal 09 febbraio 2002
Contributi
ah, quindi un singolo Context deve contenere le regole di tutte le tabelle.

Esatto, o almeno le tabelle che vuoi mappare.
Un dbcontext rappresenta un insieme di classi di entità inerenti tra loro. Le tue classi di entità Magazzini e PlanimetriaMagazzini sono certamente inerenti tra loro e appartengono entrambe all'ambito della gestione del magazzino e perciò è corretto che si trovino nello stesso dbcontext.

Puoi creare un altro dbcontext nel momento in cui introduci un altro ambito nella tua applicazione: ad esempio la "fatturazione" potrebbe essere considerata un altro ambito, distinto da quello della gestione del magazzino, e quindi è corretto creare un nuovo dbcontext per tenere logicamente separati i due ambiti.


però a me piaceva l'idea di utilizzare un singolo Context per ogni tabella,

Assolutamente no. Il design della tua applicazione non deve essere influenzato da quanto sembra elegante il codice. Il design del software deve essere influenzato unicamente dal dominio che vai a modellare.

Quindi, mantieni un solo DbContext e sposta il mapping di ciascuna entità in una propria classe di configurazione che implementa IEntityTypeConfiguration<T>. Questa classe la puoi ovviamente definire in un proprio file .cs.
Segui questo script di Stefano, è quello che ti serve.
http://www.linqitalia.com/script/457/Creare-Classi-Mapping-Entity-Framework-Core-2.0.aspx

ciao,
Moreno
Modificato da BrightSoul il 26 ottobre 2018 14.20 -

Enjoy learning and just keep making

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.