xbrossard
xbrossard

Reputation: 9

select a specific graph of objects using linq

I have a classic graph of business objects connected like this one:

public enum TypeVoie
{
    rue,
    avenue,
    route,
    împasse
}

public class Ville
{
    string nom;

    public string Nom { get { return nom; } }

    string codePostal;
    bool capital;


    public  string  id()
    {
        return nom + codePostal + capital.ToString();
    }
}

/// <summary>
/// classe composé
/// </summary>
public class Adresse
{
    int noRue;
    string nomRue;
    TypeVoie typeVoie;
    public  Ville ville { get; set; }

    public  Personne habitant { get; set; }

    public Personne Habitant { get => habitant; set => habitant = value; }

    public  string  id()
    {
        return noRue.ToString() + nomRue + typeVoie.ToString() + ville.id();
    }
}

/// <summary>
/// classe de base composant
/// </summary>
public class Personne
{
    /// <summary>
    /// l'attribut ne marche pas
    /// </summary>
    public string nom { get; set; }

    public string prenom { get; set; }

    Dictionary<string, Adresse> adresses = new Dictionary<string, Adresse>();

    public Dictionary<string, Adresse> Adresses { get => adresses; set => adresses = value; }

}

/// <summary>
/// classe composant
/// </summary>
public class Patient: Personne
{
    private static   int no = 0;

    private string noSS;
    public string IPP;

    public string NoSS { get => noSS; set => noSS = value; }

    public  string  LibelleIdentifiant { get; set; }
}

after that, i define a memory model of this object graph

/// <summary>
/// initialize a model
/// </summary>
public class InitModel1: InitModel
{
    public Patient patient1;
    public Patient patient2;
    public Patient patient3;
    public Patient patient4;
    public List<Patient> patients = new List<Patient>();

    public  InitModel1()
    {
        Ville paris = new Ville("Paris", "78000", true);
        Ville lyon = new Ville("Lyon", "69000", false);

        Adresse adresse1 = new Adresse(10, "rue de la paix", TypeVoie.rue, paris);
        Adresse adresse2 = new Adresse(69, "rue marietton", TypeVoie.rue, lyon);
        Adresse adresse3 = new Adresse(35, "avenue de saxe", TypeVoie.avenue, lyon);

        patient1 = new Patient("Berton", "isabelle", adresse1, "22372727320");
        patient2 = new Patient("moussu", "marthe", null, null);
        patient3 = new Patient("mornard", "xavier", adresse2, "66666242");
        patient4 = new Patient("gallot", "frederic", adresse3, "45313248");

        Adresse adresse4 = new Adresse(28, "impasse bellevue", TypeVoie.împasse, lyon);
        patient4.Adresses.Add(adresse4.id(), adresse4);

        patients.Add(patient1);
        patients.Add(patient2);
        patients.Add(patient3);
        patients.Add(patient4);
    }
}

I want to make a linq request to a graph of objects in memory, in order to make a partial copy of the model. So I wrote a linq request like this:

 List<Patient> patientsCherches = patients;

 var patientsTrouves = (from p in patientsCherches
                        where p.lstAddresses.FirstOrDefault(a => a.ville.Nom == "Lyon") != null
                         select p)
                                 .ToList();

the request works and return only patient with good adress, but I have two problems with this request:

Upvotes: 0

Views: 223

Answers (1)

Martin Zikmund
Martin Zikmund

Reputation: 39092

If the query was going to the database, this filtering could be done on the server side. In this case however the data is already in memory, so you will have to create a new instance if you don't want to lose data from the original instance.

Only selected address

You will create a new Patient instance and set the list of addresses to a filtered result.

var patientsTrouves = (from p in patientsCherches
             where p.lstAddresses.FirstOrDefault(a => a.ville.Nom == "Lyon") != null
             select new Patient( /* initialize patient using "p" values */ ) { IPP = p.IPP, NoSS = p.NoSS, 
             lstAddresses = p.lstAddresses.Where( a => a.ville.Nom == "Lyon" ).ToList() } )
                                 .ToList();

Only the patient without addresses

Here you can simply create a new patient instance without initializing the list of addresses.

var patientsTrouves = (from p in patientsCherches
             where p.lstAddresses.FirstOrDefault(a => a.ville.Nom == "Lyon") != null
             select new Patient( /* initialize patient using "p" variable */ ) )
                                 .ToList();

Additional suggestions

I have a few additional suggestions for your code, just as potential improvements to get the readability better:

  • Make a clear naming convention. Usually properties and methods use PascalCasingConvention (each word has capital first letter), while private fields use camelCasingConvention (each word has capital first letter except the first one)
  • Ideally method names should include verbs to indicate the fact they perform an action and that they are in fact methods, not properties. For example Id() would be more readable as GetId()
  • Name of the property should be self descriptive and doesn't have to describe the data type if not necessary - lstAddresses is not necessary, you can use just Addresses instead, as it is clear there is more of them.
  • Avoid public fields like IPP. You can almost always use a public property instead. It is more future-proof.
  • Instead of FirstOrDefault( condition ) != null you can use Any( condition )

Upvotes: 2

Related Questions