2017-09-24 3 views
0

La documentation Realm donne un exemple de backlinks utilisant un objet person et un objet dog. Si j'étends cela pour inclure aussi les chats, alors une personne peut avoir plusieurs chiens ou chats à marcher, et chaque chien ou chat peut être promené par plusieurs personnes différentes.Domaine de requête avec plusieurs backlinks

public class Dog : RealmObject 
{ 
    public string Name { get; set; } 

    [Backlink(nameof(Person.Dogs))] 
    public IQueryable<Person> Walkers { get; } 
} 

public class Cat : RealmObject 
{ 
    public string Name { get; set; } 

    [Backlink(nameof(Person.Cats))] 
    public IQueryable<Person> Walkers { get; } 
} 

public class Person : RealmObject 
{ 
    //... other properties (name, age, address, etc.) 
    public IList<Dog> Dogs { get; } 
    public IList<Cat> Cats { get; } 
} 

À l'aide des backlinks me permet d'obtenir une liste de personnes qui marchent le chien Fido ...

var fidoWalkers = realm.All<Dog>().Where(d => d.Name == "Fido").FirstOrDefault().Walkers; 

Je peux maintenant élargir davantage cette requête pour trouver les marcheurs de Fido qui vivent dans High Street ou qui ont moins de 30 ans ou quoi que ce soit ... génial jusqu'ici.

Maintenant, je veux obtenir une liste des personnes qui promènent le chien Fido et le chat Moggie. En utilisant les backlinks dans deux déclarations distinctes, j'ai pu obtenir deux ensembles de résultats, un pour les marcheurs Fido et un pour les marcheurs Moggie, mais je ne sais pas comment les combiner. Je ne puis trouver une requête qui me permettrait de faire ce « le long chemin rond » sans utiliser les backlinks, car chaque fois que j'essaie d'utiliser

...Where(P => p.Dogs.Contains(Fido))... 

Je reçois « System.NotSupportedException: La méthode CONTAINS est non pris en charge '

Existe-t-il un moyen d'obtenir une liste de personnes filtrées par les listes Chiens et Chats?

Répondre

0

Bien qu'il ya beaucoup de choses la version .Net de Realm fait bien, il y a des limites dans le support Linq et donc vous êtes obligé de matérialiser les paresseux chargé IRealmCollection à un List dur (ou un tableau) par l'intermédiaire LINQ to Objects afin d'effectuer projections, jointures, comparaisons IEqualityComparer, etc ... ceci inclut les backlinks et les propriétés IList basées sur RealmObject.

A lire Realm-dotnet document: LINQ support in Realm Xamarin

Vous pourrait ajouter quelques propriétés qui effectuent une projection Linq à une liste de chaînes (noms d'animaux, bien sûr en supposant qu'ils sont des clés uniques):

public class Person : RealmObject 
{ 
    //... other properties (name, age, address, etc.) 
    public IList<Dog> Dogs { get; } 
    public IList<Cat> Cats { get; } 

    public List<string> DogList => Dogs.ToList().Select(_ => _.Name).ToList(); 
    public List<string> CatList => Cats.ToList().Select(_ => _.Name).ToList(); 
} 

Et puis prenez votre requête de personne à une liste et utilisez Contains sur les listes de chaînes matérialisées par rapport aux propriétés RealmCollection.

var walkers = realm.All<Person>().ToList().Where(_ => _.CatList.Contains("Garfield") && _.DogList.Contains("Fido")); 
foreach (var walker in walkers) 
{ 
    Log.Debug(TAG, $"{walker}"); 
} 

Vous pouvez également créer deux requêtes, un filtre sur le backlink nom du chien et des chats pour l'autre, matérialisé toutes les collections pour chiens et chats sur chaque personne dans les deux requêtes, effectuez une Distinct via une coutume IEqualityComparer.

Une fois que vous avez copié les objets de royaume dans des listes indépendantes/tableaux, à peu près toute solution Linq fonctionnera ...

L'inconvénient de tout cela est le filtrage est en cours d'exécution en mémoire ainsi vous prenez un La mémoire et le processeur sont coupés car vous n'êtes pas capable d'utiliser les fonctions de requête natives de Realm ...

Personnellement, je remodéliserais les RealmObject pour fournir aux gens qui marchent des animaux et donc aux animaux des génériques et qui à leur tour fournissent des liens à particulier Dog and Cat RealmObjects qui fournissent une spécialisation. Mais c'est totalement sans connaître votre objectif final ...

+0

Grande réponse merci - maintenant je comprends beaucoup mieux. Mes modèles actuels sont évidemment beaucoup plus complexes (en fait, un catalogue d'objets de couture, chacun avec plusieurs types de vêtements, types de tissus, catégories et étiquettes, etc.) mais je vais examiner les aspects pratiques de la modification de la structure du modèle. de l'exécution des requêtes LINQ sur les listes en mémoire. Encore quelques expérimentations ... – sparks

+0

@sparks Pas de problème, Personnellement, je pense que l'une des choses requises pour une utilisation mémoire/CPU optimale lors de l'utilisation de Realm est la possibilité de concevoir votre modèle de domaine qui correspond au modèle d'utilisation de votre application. Quand un client dit que le modèle ne peut * pas * changer ** la période **, je me tourne vers SQLite. Lorsque nous avons la liberté de repenser le modèle du point de vue de l'utilisation d'une application, Realm peut être étonnant en termes de performance, d'utilisation d'objets "live", etc ... mais habituellement le modèle original se termine (fortement) dé-normalisé et nous créons une carte de données sur le serveur pour gérer la sérialisation/désérialisation JSON ... – SushiHangover

+0

@sparks En termes de 'pattern d'utilisation de l'application', je regarde ce qui est affiché par page, écran, table, Activity, Fragment, UITableView, etc ... et c'est le début de mon modèle de royaume pour chaque vue d'application. Si elle n'est pas affichée à l'écran, triée par, ou une clé primaire/cachée utilisée pour l'API/sync/etc ... Je ne l'inclue pas. Une fois que toutes les informations sont affichées dans l'application, il devient "facile" ;-) de modéliser tous ces petits fragments en un modèle consolidé normalisé qui est très performant .... Les versions d'applications qui changent le modèle sont gérer via les migrations de domaine. – SushiHangover