88 messaggi dal 18 aprile 2018
Salve a tutti, sto realizzando un applicazione MVC che permetta agli utenti registrati di prendere appuntamenti, per farlo ho creato una tabella Appointment e messa in relazione con AspnetUser ma dal controller non riesco a mandare l'id dell'utente.
Vi mostro il codice cosi da spiegarvi meglio.
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;

namespace toilette.Models
{
    // È possibile aggiungere dati del profilo per l'utente aggiungendo altre proprietà alla classe ApplicationUser. Per altre informazioni, vedere https://go.microsoft.com/fwlink/?LinkID=317594.
    public class Appointment
    {
       
        public int AppointmentId { get; set; }
        public string text { get; set; }

       
        public virtual ApplicationUser ApplicationUser { get; set; }
    }

    public class ApplicationUser : IdentityUser
    {
        public virtual Appointment Appointment { get; set; }
        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
        {
            // Tenere presente che il valore di authenticationType deve corrispondere a quello definito in CookieAuthenticationOptions.AuthenticationType
            var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
            // Aggiungere qui i reclami utente personalizzati
            return userIdentity;
        }
    }

    public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        public ApplicationDbContext()
            : base("DefaultConnection", throwIfV1Schema: false)
        {
        }
        public DbSet<Appointment> Appointments { get; set; }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            // one-to-zero or one relationship between ApplicationUser and Customer
            // UserId column in Customers table will be foreign key
            modelBuilder.Entity<ApplicationUser>()
                .HasOptional(m => m.Appointment)
                .WithRequired(m => m.ApplicationUser)
                .Map(p => p.MapKey("UserId"));
        }
        public static ApplicationDbContext Create()
        {
            return new ApplicationDbContext();
        }
    }
}


Si crea la riga UserId nella tabella Appointment, se inserisco manualmente l'id dell'utente nel DB funziona e riesco nel nella visualizzazione e mostrare solo gli appuntmanti dell'utente registrato.
Ma dal controller Appointments non riesco a mandargli l'id utente in modo che questo possa creare l'appuntamento dalla visualizzazione.
(se provo dalla visualizzazione a creare l'appuntmanto mi ritorna questo errore:
Le entità in 'ApplicationDbContext.Appointments' fanno parte della relazione 'ApplicationUser_Appointment'. Trovati 'ApplicationUser_Appointment_Source' correlati a 0. Previsto 1 'ApplicationUser_Appointment_Source'.)
Grazie in anticipo per chi vorrà aiutarmi
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,
ogni utente può avere avere molteplici appuntamenti? Se è questo il caso, dovresti sostituire HasOptional con HasMany. Al momento, infatti, stai creando una relazione uno a uno, mentre a te probabilmente serve uno a molti.


Trovati 'ApplicationUser_Appointment_Source' correlati a 0. Previsto 1 'ApplicationUser_Appointment_Source'.)

Se crei relazioni uno a uno, l'AppointmentId deve essere valorizzato con l'id dell'utente, non può essere un intero autoincrementante.


ciao,
Moreno

Enjoy learning and just keep making
88 messaggi dal 18 aprile 2018
Ciao Moreno, grazie della risposta, in realtà si ho bisogno di creare la relazione uno a molti..
Ho seguito molte guide ma non sono mai riuscito, come posso fare questa relazione?
Ho provato anche a lasciare la definizione cosi come era quindi con .HasOptional ma nulla non vado avanti.


public class Appuntamento
    {
        [Key]
        public int idAppuntamento { get; set; }
        
      //  public string UserId{ get; set; } // questo immagino dovrebbe essere la chiave di collegamento\

        public string Testo { get; set; }
        public int idServizio { get; set; }
        [ForeignKey("idServizio")]
        public Servizio servizi { get; set; }
        public DateTime Start_Data { get; set; }
        public DateTime End_Data { get; set; }
        
  public virtual ApplicationUser ApplicationUser { get; set; }
    }

    public class ApplicationUser : IdentityUser
    {
        public virtual Appuntamento Appuntamenti { get; set; }
     
        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
        {
            // Tenere presente che il valore di authenticationType deve corrispondere a quello definito in CookieAuthenticationOptions.AuthenticationType
            var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
            // Aggiungere qui i reclami utente personalizzati
             
            return userIdentity;
        }
    }

    public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        public ApplicationDbContext()
            : base("DefaultConnection", throwIfV1Schema: false)
        {
        }
        
        public DbSet<Appuntamento> Appuntamenti { get; set; }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            // one-to-zero or one relationship between ApplicationUser and Customer
            // UserId column in Customers table will be foreign key
            modelBuilder.Entity<ApplicationUser>()
                .HasMany(m => m.Appuntamenti) //segnalato come rosso
                .WithRequired(m => m.ApplicationUser)
                .Map(t=>t.MapKey("UserId"));

            

        }

        public static ApplicationDbContext Create()
        {
            return new ApplicationDbContext();
        }

     
      
        
    }

Naturalmente ho lo stesso problema di prima non riuscendo a popolare l'UserId
Grazie mille per il tuo tempo
Modificato da Mirko2018 il 25 aprile 2018 00.19 -
Modificato da Mirko2018 il 25 aprile 2018 00.29 -
Modificato da Mirko2018 il 25 aprile 2018 02.01 -
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao, segui queste istruzioni per mappare la relazione uno a molti:

http://www.entityframeworktutorial.net/code-first/configure-one-to-many-relationship-in-code-first.aspx

Nella classe Appuntamento, prova a decommentare la proprietà UserId che giustamente hai messo. Poi, mappa così la relazione nel metodo OnModelCreating.
modelBuilder
  .Entity<Appuntamento>()
  .HasRequired(m => m.ApplicationUser)
  .WithMany()
  .HasForeignKey(a => a.UserId);


Vedi che in WithMany non ho indicato alcun parametro. Questo perché in ApplicationUser non hai creato una collezione Appointments, motivo per cui te lo segnava rosso. Comunque, non è obbligatorio creare la colluzione, e può andar bene così. La crei solo se hai bisogno di accedere agli appuntamenti di un utente partendo da un oggetto ApplicationUsers.

Nota: per mappare le relazioni dovresti usare o gli attributi o l'interfaccia fluente, per coerenza. Vedo invece che stai usando un mix: nella classe Appuntamento hai mappato la relazione con Servizio usando gli attributi, mentre invece la relazione con ApplicationUser l'hai mappata dal metodo OnModelCreating, usando l'interfaccia fluente.

ciao,
Moreno
Modificato da BrightSoul il 25 aprile 2018 09.37 -

Enjoy learning and just keep making
88 messaggi dal 18 aprile 2018
Diciamo che è ok ovvero il campo UserId in Appuntamenti è obbligatorio però mi hai dato un buon input e anche se mi ha creato anche nella cartella AspNetUsers una colonna che non mi serve sta funzionando lo stesso quindi diciamo che per il momento mi accontento e piano piano lo miglioro.

Approfitto della tua gentilezza, se posso chiedere sempre a te... ho inserito il fullcalendar va tutto bene ma ho un piccolo problema, mi spiego, nell'index ho gestito i dati tramite jquery in modo che appaia un modal quando si clicca sull'evento con i dati reltivi all'appuntamento.. il problema è che chiaramente mi viene mostrato l'id e non il nome dell'utente tra i dettagli, non sono riuscito a fare il join per averlo come risultato. Ti posto il codice:
Nell'index:

            function GenerateCalender(events) {
                $('#calender').fullCalendar('destroy');
                $('#calender').fullCalendar({
                    contentHeight: 400,
                    defaultDate: new Date(),
                    timeFormat: 'h(:mm)a',
                    header: {
                        left: 'prev,next today',
                        center: 'title',
                        right: 'month,basicWeek,basicDay,agenda'
                    },
                    eventLimit: true,
                    eventColor: '#378006',
                    events: events,
                    eventClick: function (calEvent, jsEvent, view) {
                        selectedEvent = calEvent;
                        $('#myModal #eventTitle').text(calEvent.title);
                        var $description = $('<div/>');
                        $description.append($('<p/>').html('<b>Start:</b>' + calEvent.start.format("DD-MMM-YYYY HH:mm a")));
                        if (calEvent.end != null) {
                            $description.append($('<p/>').html('<b>End:</b>' + calEvent.end.format("DD-MMM-YYYY HH:mm a")));
                        }

                        $description.append($('<p/>').html('<b>Description:</b>' + calEvent.description));
                        $description.append($('<p/>').html('<b>UserId:</b>' + calEvent.UserId));
                        
                        $('#myModal #pDetails').empty().html($description);

                        $('#myModal').modal();
                    },
                    selectable: true,
                    select: function (start, end) {
                        selectedEvent = {
                            eventID: 0,
                            title: '',
                            description: '',
                            start: start,
                            end: end,
                            allDay: false,
                            color: ''
                        };
                        openAddEditForm();
                        $('#calendar').fullCalendar('unselect');
                    },
                    editable: true,
                    eventDrop: function (event) {
                        var data = {
                            EventID: event.eventID,
                            Subject: event.title,
                            Start: event.start.format('DD/MM/YYYY HH:mm A'),
                            End: event.end != null ? event.end.format('DD/MM/YYYY HH:mm A') : null,
                            Description: event.description,
                            ThemeColor: event.color,
                            IsFullDay: event.allDay
                        };
                        SaveEvent(data);
                    }
                })
            }



Nel controller:

 public JsonResult GetEvents()
        {
            using (Entities dc = new Entities())
            {
                var events = dc.Events.ToList();
                return new JsonResult { Data = events, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
            }
        }


qui mi restituisce la stringa con l'id e che dovrei convertire con il nome dell'utente:

                        $description.append($('<p/>').html('<b>UserId:</b>' + calEvent.UserId));



Grazie mille del tuo tempo.
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,
non dovresti restituire al client le entità così come sono. Questo non andrebbe fatto...

using (Entities dc = new Entities())
{
var events = dc.Events.ToList();
return new JsonResult { Data = events, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}


Quindi dovresti crearti una nuova classe che puoi chiamare EventDto (o come vuoi tu) in cui metti soltanto le proprietà che servono al FullCalendar, tipo la data, il titolo e il nome dell'utente. Se non facessi così, rischieresti di divulgare al client più dati del necessario.

Quindi, devi operare una proiezione con il metodo Select che ti trasformerà l'entità Event nel tipo EventDto.

non sono riuscito a fare il join

Dimentica le join, quello è un concetto del mondo relazionale. Qui sei nel mondo concettuale e per ottenere i dati di entità correlate si usando le proprietà di navigazione.
Ti ricordi? Quando abbiamo mappato la relazione tra Appuntamento e Utente abbiamo indicato " .HasRequired(m => m.ApplicationUser)". Quella ApplicationUser è appunto la proprietà di navigazione che ti porta ad accedere ai dati dell'utente senza dover fare join esplicite.

Quindi, prova così. Vado a braccio quindi è probabile che il codice sia sbagliato. Cerca di carprirne l'intento.
using (Entities dc = new Entities())
{
  var events = dc.Events.
   Select(e => new EventDto {
      Id = e.Id,
      Title = e.Title,
      Username = e.ApplicationUser.Username,
      Date = e.Date
   }).ToList();
  return new JsonResult { Data = events, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}


EventDto sarà una nuova classe definita così:
public class EventDto {
  public int Id { get; set; }
  public string Title { get; set; }
  public string Username { get; set; }
  public DateTime Date { get; set; }
}


ciao,
Moreno

Enjoy learning and just keep making
88 messaggi dal 18 aprile 2018
Buona sera Moreno,
dovrei approfittare ancora una volta della tua conoscenza....
con gli aiuti che mi hai dato tutto ok e ti ringrazio, adesso oltre alla tabella appuntamenti che funziona senza problemi sto inserendo le note quindi la possibilita di assegnare più note ad ogni utente, quando però creo il controller note (che ho impostato esattamente come appuntamenti) e creo un nuova nota al momento della creazione mi da un errore: Riferimento a un oggetto non impostato su un'istanza di oggetto. L'errore lo segnala nel controller nota in questo punto...
Riga 58:             }
Riga 59: 
Riga 60:             ViewBag.UserId = new SelectList(db.Users, "Id", "Nome", nota.UserId);
Riga 61:             return View(nota);
Riga 62:         }

Ma il controller appuntamenti e le caratteristiche nell'identity sono le stesse identiche ma questo non funziona non sono perchè... ti allego il codice dell'identity di entrambi:
 [Table("Appuntamenti")]
    public class Appuntamento
    {
        [Key]
        public int idAppuntamento { get; set; }
        public string UserId { get; set; }
        public virtual ApplicationUser ApplicationUser { get; set; }

        public string Descrizione { get; set; }
        public int idServizio { get; set; }
        [ForeignKey("idServizio")]
        public Servizio servizi { get; set; }
        public DateTime Start_Data { get; set; }
        public DateTime End_Data { get; set; }
        public string ThemeColor { get; set; }
        public bool IsFullDay { get; set; }


    }

    [Table("Note")]
    public class Nota
    {
        [Key]
        public int idNota { get; set; }
        public string nota { get; set; }
        public DateTime dataIns { get; set; }
        public string UserId { get; set; }

        public virtual ApplicationUser ApplicationUser { get; set; }
    }


    public class ApplicationUser : IdentityUser
    {
        public string Nome { get; set; }
        public string Cognome { get; set; }

        public string Telefono { get; set; }
        public virtual Appuntamento Appuntamenti { get; set; }
        public virtual Nota Note { get; set; }
        public virtual ICollection<Card> Cards { get; set; }
        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
        {
            // Tenere presente che il valore di authenticationType deve corrispondere a quello definito in CookieAuthenticationOptions.AuthenticationType
            var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
            // Aggiungere qui i reclami utente personalizzati

            return userIdentity;
        }
    }

    public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        public ApplicationDbContext()
            : base("DefaultConnection", throwIfV1Schema: false)
        {
        }
        public DbSet<Nota> Note { get; set; }
        public DbSet<Animale> Animali { get; set; }
        public DbSet<Promozione> Promozioni { get; set; }
        public DbSet<Spesa> Spese { get; set; }
        public DbSet<Prodotto> Prodotti { get; set; }
        public DbSet<Card> Cards { get; set; }
        public DbSet<Appuntamento> Appuntamenti { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            // one-to-zero or one relationship between ApplicationUser and Customer
            // UserId column in Customers table will be foreign key
            modelBuilder
              .Entity<Appuntamento>()
              .HasRequired(m => m.ApplicationUser)
              .WithMany()
              .HasForeignKey(a => a.UserId);

            modelBuilder
              .Entity<Nota>()
              .HasRequired(m => m.ApplicationUser)
              .WithMany()
              .HasForeignKey(a => a.UserId);



        }

        public static ApplicationDbContext Create()
        {
            return new ApplicationDbContext();
        }

        public System.Data.Entity.DbSet<Toeletta10.Models.Servizio> Servizi { get; set; }

    }
}


il controller appuntamenti che funziona :
 // GET: Appuntamenti/Create
        public ActionResult Create()
        {
            ViewBag.UserId = new SelectList(db.Users, "Id", "Nome");
            ViewBag.idServizio = new SelectList(db.Servizi, "idServizio", "nomeServizio");
            return View();
        }

        // POST: Appuntamenti/Create
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see https://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include = "idAppuntamento,UserId,Descrizione,idServizio,Start_Data,End_Data,ThemeColor,IsFullDay")] Appuntamento appuntamento)
        {
            if (ModelState.IsValid)
            {
                db.Appuntamenti.Add(appuntamento);
                db.SaveChanges();
                return RedirectToAction("Index");
            }

            ViewBag.UserId = new SelectList(db.Users, "Id", "Nome", appuntamento.UserId);
            ViewBag.idServizio = new SelectList(db.Servizi, "idServizio", "nomeServizio", appuntamento.idServizio);
            return View(appuntamento);
        }


e il controller Note che NON FUNZIONA :

// GET: Note/Create
        public ActionResult Create()
        {
            ViewBag.UserId = new SelectList(db.Users, "Id", "Nome");
            return View();
        }

        // POST: Note/Create
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see https://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include = "idNota,nota,dataIns,UserId")] Nota nota)
        {
            if (ModelState.IsValid)
            {
                db.Note.Add(nota);
                db.SaveChanges();
                return RedirectToAction("Index");
            }
// Qui segnala l'errore
            ViewBag.UserId = new SelectList(db.Users, "Id", "Nome", nota.UserId);
            return View(nota);
        }


so del consiglio che mi hai dato di usare solo le fluent api ma le sto studiando poi le sostituirò tutte.
grazie mille del tuo tempo
Mirko
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao Mirko,


ferimento a un oggetto non impostato su un'istanza di oggetto. L'errore lo segnala nel controller nota in questo punto...
Riga 58: }
Riga 59:
Riga 60: ViewBag.UserId = new SelectList(db.Users, "Id", "Nome", nota.UserId);
Riga 61: return View(nota);
Riga 62: }


Ok, vuol dire che la variabile nota è null. Inoltre, se l'esecuzione è arrivata alla riga 60 vuol dire che ModelState.IsValid è false, ma questo è normale dato che nota è null.

La variabile nota viene assegnata dal model binder di ASP.NET MVC in base alle informazioni che sono state inviate con il form. Dato che non ci è riuscito, La prima idea che mi viene in mente è che nel form non abbia trovato le informazioni giuste. Il problema quindi va ricercato lato client.

Per il momento risolvi il problema con commentando la riga 60, poi usa gli strumenti di sviluppo del browser (tasto F12) e vai nella scheda "Rete" o "Network" per capire cosa sta inviando il client al server. Ispeziona le chiavi inviate col post e poi riporta qui quello che hai scoperto.
Potrebbe essere ad esempio che non stai inviando un valore valido per dataIns, che deve essere interpretabile come data/ora.

ciao,
Moreno
Modificato da BrightSoul il 27 maggio 2018 10.49 -

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.