1
votes

EF Core peut-il mapper une propriété GET (calculée)?

J'ai une classe de modèle qui contient un tableau d'objets que je souhaite stocker dans la base de données. Afin d'ajuster ces données dans une seule ligne et colonne; J'ai une propriété get qui concatène le tableau et renvoie une seule chaîne. Je souhaite stocker cette chaîne concaténée dans la base de données.

[NotMapped]
public object[] Values { get; set; }

public string Value
{
    get
    {
        return string.Join("|", this.Values);
    }
}

J'ai confirmé que la propriété Value contient la chaîne que j'attends. Cependant, cela n'enregistre pas dans la base de données; il l'enregistre simplement comme NULL. Je n'ai pas de code de mappage spécial en place; il repose sur les valeurs par défaut du fait que le nom de la colonne correspond au nom de la propriété.

La chose la plus proche que je l'ai trouvée ce tutoriel qui décrit l'utilisation de la méthode HasField () pour mapper la colonne à un champ privé au lieu d'une propriété; mais dans mon cas, ce n'est pas seulement que j'ai un poste privé; c'est que je n'ai pas du tout de propriété définie.


7 commentaires

Pourquoi ne définissez-vous pas simplement le champ string Value dans la méthode set de object [] Values ​​ également?


@ AdolfoF.IbarraLandeo J'ai eu cette idée presque juste après avoir posté la question ... puisque l'objet est créé en analysant automatiquement Json avec Newtonsoft, je n'étais pas sûr si cela aurait un problème avec une propriété plus complexe qu'un normal get / set; mais cela semble fonctionner !. Je suis toujours curieux de connaître la question telle que posée; parce que cela semble être une solution de contournement; et cela ne fonctionnerait pas si, par exemple, la propriété get-only n'était pas simplement calculée en fonction d'une autre propriété que j'ai déjà.


@Gendolkari, pouvez-vous expliquer ce que vous voulez dire par la dernière chose que vous avez dite? Voulez-vous dire si la Valeur doit être calculée à l'aide de plusieurs propriétés?


En tant qu'exemple trivial mais peut-être pas utile, que se passe-t-il si Value renvoie DateTime.Now à la place? Ou, oui, comme si la valeur était basée sur plusieurs propriétés.


Aucun champ de sauvegarde n'a été trouvé pour la propriété 'SomeValue' du type d'entité 'MyEntity' et la propriété n'a pas de setter . Peut-être que cela explique un peu EF Core. Il semble que vous deviez spécifier un setter pour une propriété mappée. Donc, dans tous les cas, le setter doit définir la valeur en utilisant les propriétés que vous souhaitez utiliser et récupérer cette valeur avec l'accesseur get


Je suppose qu'un exemple plus réaliste mais toujours simple serait si vous aviez des propriétés régulières FirstName et LastName, ainsi qu'un FullName {get {return $ "{FirstName} {LastName}";}} et que vous vouliez stocker FullName dans la base de données.


Eh bien, dans ce cas, vous avez deux options: 1: Créez un setter vide et laissez la logique de retour dans l'accesseur get, comme @Claudio Valerio l'a suggéré (pour des scénarios simples) 2: Créez un setter pour cette propriété afin de prendre les valeurs des propriétés souhaitées et de stocker le résultat dans un champ privé, puis récupérez ce dernier à partir de l'accesseur get. (pour des scénarios plus complexes).


3 Réponses :


1
votes

Pourquoi ne faites-vous pas quelque chose comme ça?

private object[] values;

[NotMapped]
public object[] Values { 
    get => values;
    set {
        if (value != values);
        values = value;
        Value = string.Join("|", value);
    }
}

public string Value { get; set; }


1 commentaires

Lorsque je crée une nouvelle instance, cela fonctionnerait-il correctement? var object = new MyObject {Values ​​= new [] {"one", "two"}, Value = "Another values"}



1
votes

Vous pouvez tromper EF en faisant quelque chose comme ceci:

[NotMapped]
public object[] Values { get; set; }

public string Value
{
    get
    {
        return string.Join("|", this.Values);
    }
    set {}
}

Setter ne fera rien, donc vous obtenez ce que vous voulez.


1 commentaires

Je suis en fait surpris que cela fonctionne, mais c'est le cas! Cela semble un peu plus piraté que l'autre solution; bizarrerie très étrange dans EF apparemment.



1
votes

Une autre approche pour ne pas mélanger les structures d'entreprise et de persistance.

Les autres parties de l'application doivent se soucier / savoir comment les données sont stockées.

public class BusinessObject
{
    public object[] Values { get; set; }
}

public class ValuesEntity
{
    public static ValuesEntity From(BusinessObject object)
    {
        return new ValuesEntity { Values = string.Join("|", object.Values) };
    }

    public string Values { set; set; }

    public BusinessObject ToBusinessObject()
    {
        return new BusinessObject { Values = Values.Split("|") };
    }
}

Avec cette approche, vous "informerez" explicitement d'autres développeurs ou lecteurs du code de vos intentions.
Travailler avec différentes classes pour chaque responsabilité (logique métier ou persistance) sera plus simple car les deux responsabilités sont isolées l'une de l'autre.


0 commentaires