2 messaggi dal 17 marzo 2022
Ciao a tutti,
sto studiando in questi giorni l'utilizzo di EF Core e sto riscontrando dei problemi con un caso particolare in cui una tabella sul database deve gestire una chiave univoca composta da una chiave esterna e un campo. Di seguito un esempio

    [Index(nameof(CreationDate))]
    [Index(nameof(UserName))]
    public class Job
    {
        public Guid JobID { get; set; }

        [Required]
        public DateTime CreationDate { get; set; }
        [Required]
        public string UserName { get; set; } = "";
    }

    [Index(nameof(Job ), nameof(TargetName), IsUnique = true)]
    public class JobActivity
    {
        public Guid JobActivityID { get; set; }

        [Required]
        public Job? Job { get; set; } = new Job();

        [Required]
        public string TargetName { get; set; } = "";
    }



Questo pezzettino di codice mi manda in errore il comando da CLI "dotnet ef migration ..." perche il provider non supporta l'istruzione [Index(nameof(Job ), nameof(TargetName), IsUnique = true)] in quanto Job è una classe. Premetto che sto utilizzando un database MySql e come provider EF "Pomelo.EntityFrameworkCore.MySql" che è quello che mi ha dato più soddisfazione con i comandi da CLI.

Io personalmente ho trovato (sfruttando la mia immaginazione :D) la seguente soluzione
    [Index(nameof(CreationDate))]
    [Index(nameof(UserName))]
    public class Job
    {
        public Guid JobID { get; set; }

        [Required]
        public DateTime CreationDate { get; set; }
        [Required]
        public string UserName { get; set; } = "";
    }

    [Index(nameof(RefJob), nameof(TargetName), IsUnique = true)]
    public class JobActivity
    {
        public Guid JobActivityID { get; set; }

        [Required]
        public Job? Job { get; set; } = new Job();

        [Required]
        public Guid? RefJob
        {
            get => Job?.JobID;
            set
            {

            }
        }

        [Required]
        public string TargetName { get; set; } = "";
    }


Il trick quindi è usare un campo "fittizzio" dato a contenere la chiave specificata dalla classe Job. Il codice pare funzionare bene con la classiche operazioni di R/W ma ovviamente ho lo svantaggio di avere due colonne duplicate che in realtà a livello di DB non sono necessarie.

Le domande essenzialmente sono due :
1) I problemi che sto riscontrando sono dovuti esclusivamente al provider che sto utilizzando (Pomelo in questo caso) e ad esempio con quello per SqlServer non avrei lo stesso problema?
2) Esiste una soluzione più elegante per risolvere questo problema?

Ciao :)
Modificato da alfaman il 17 marzo 2022 07:02 -
829 messaggi dal 08 aprile 2009
Nella classe del model puoi anche dichiarare delle colonne che sono classi ma sostanzialmente nel database devi prevedere il salvataggio di una stringa che poi in fase di scrittura e lettuara serializzi e deserializzi.

Quindi quando crei il modello istruisci EF Core nella conversione del dato in lettura e scrittura.
Ad esempio puoi serializzare e deserializzare in formato json.

Quindi nel Model dichiari il dato con la tua classe
        [Required]
        public Job? Job { get; set; } = new Job();


Nel builder del model

 modelBuilder.Entity<Tabella>(entity =>
            {
                entity.Property(p => p.Job)
               .HasConversion(
                   entity => JsonSerializer.Serialize(entity, null),
                    value => JsonSerializer.Deserialize<Job>(value, null));
});
2 messaggi dal 17 marzo 2022
Grazie laurar181 per questa risposta che mi ha fatto prendere coscienza del del fatto che non necessariamente devo mappare una composizione di oggetti su tabelle distinte .. e probabilmente questo è anche una soluzione interessante per mappare su mysql il tipo dati Json verso una classe che compare come attributo dell'entità che si sta' gestendo,

Tuttavia credo di non essermi spiegato bene sul problema che ho. Il problema che ho sul mapping è solo sulla creazione della chiave univoca composta che vorrei creare sulla tabella JobsActivity che toericamente dovrei scrivere con la seguente annotazione
 [Index(nameof(Job ), nameof(TargetName), IsUnique = true)] // teoricamente qui il provider dovrebbe usare il campo che utilizza normalmente durante il mapping come FK


proprio perché Job è una classe e il provider non sa creare questo tipo di indice univoco mentre l'istruzione

[Index(nameof(RefJob), nameof(TargetName), IsUnique = true)]


Viene gestita correttamente perchè RefJob e TargetName sono due tipi primitivi :(

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.