Implement composite key C#

Asked

Viewed 330 times

6

I’m performing some tests and managed to implement using this form:

    public class Residencia
    {
        public object Id
        {
            get { return String.Concat(Cidade, Estado); }
            set { }
        }

        private string Cidade;
        private string Estado;

        public Residencia(string cidade, string estado)
        {
            Cidade = cidade;
            Estado = estado;
        }
    }

    private static void Main(string[] args)
    {
        List<Residencia> ListaResidencia = new List<Residencia>();
        ListaResidencia.Add(new Residencia("São Paulo", "SP"));
        ListaResidencia.Add(new Residencia("Bauru", "SP"));

        var cidade = new Residencia("Bauru", "SP");

        if (ListaResidencia.Any(x => x.Id.Equals(cidade.Id)))
        {
            Console.Write("Já existe uma Residência com esses dados.");
        }
        else
        {
            ListaResidencia.Add(cidade);
        }

        ListaResidencia.Count();

        Console.ReadKey();
    }

My question is if this form I implemented is the correct one (follows the programming patterns) and if there is another way to do this (improve).

2 answers

8


I don’t think that’s the ideal way.

The . Net offers the following ways to compare the equality between two objects:

  • the virtual method Equals which can be implemented in order to compare objects to each other

  • the interface IEquatable<T>, which allows implementing the way in which two objects compare to each other.

  • the interface IEqualityComparer<T> which allows implementing a form of comparison for any other class

Example with override of Equals

public class Residencia
{
    public override bool Equals(object obj)
    {
        var other = obj as Residencia;
        if (other == null) return false;
        return this.Cidade == other.Cidade
            && this.Estado == other.Estado;
    }

    public string Cidade { get; private set; }
    public string Estado { get; private set; }

    public Residencia(string cidade, string estado)
    {
        Cidade = cidade;
        Estado = estado;
    }
}

private static void Main(string[] args)
{
    List<Residencia> listaResidencia = new List<Residencia>
    {
        new Residencia("São Paulo", "SP"),
        new Residencia("Bauru", "SP"),
    };

    var cidade = new Residencia("Bauru", "SP");

    if (listaResidencia.Contains(cidade))
    {
        Console.Write("Já existe uma Residência com esses dados.");
    }
    else
    {
        listaResidencia.Add(cidade);
    }

    listaResidencia.Count();

    Console.ReadKey();
}

Alternative using an Anonimous-type

The @Mayogax comment provides an alternative, which is more like what you did. Instead of concatenating strings, you could have used an anonymous type, which would work as a perfectly composed key:

public object Id
{
    get { return new { Cidade, Estado }; }
}

And then I could use the rest of the code the way you had done before.

Even so, I would implement the method Equals, which would change implementation to the following:

public override bool Equals(object obj)
{
    var other = obj as Residencia;
    if (other == null) return false;
    return this.Id.Equals(other.Id);
}
  • Very good Miguel! Your knowledge in C# is excellent, thank you.

  • 2

    To legitimize the answer here is the explanation on composite key following the MSDN: http://msdn.microsoft.com/pt-br/library/bb907099.aspx

  • @Mayogax: the use of an instance of an Anonimous-type is also a great option because the Equals of Anonimous-type is implemented by comparing all fields. Thank you for the additional information. = D

6

Why not use it that way?

Using a concatenation to simulate a single key is never a good idea, as it can cause ambiguity, for example:

  • Object 1 = Id1: "11", Id2: "1" => Id: "111";
  • Object2 = Id1: "1", Id2: "11" => Id: "111";

This was a silly example, but it serves to exemplify, of course you could create ways to avoid the clash of Ids, but the code would be a little confusing.

Why use Iequatable

Well, as our friend Miguel Angelo mentioned earlier, a solution that meets the good standard would be to use Iequatable, Besides being a class where you can define an efficient and robust comparison method it is an interface known by . Net and this uses it elsewhere in the form of the Design Standard Template, for example, the method Contains:

This method determines Equality by using the default Equality Comparer, as defined by the Object’s implementation of the Iequatable.Equals method for T (the type of values in the list).

What would your code look like?

    public class Residencia : IEquatable<Residencia>
    {
        public object Id
        {
            get { return String.Concat(Cidade, Estado); }
            set { }
        }

        private string Cidade;
        private string Estado;

        public Residencia(string cidade, string estado)
        {
            Cidade = cidade;
            Estado = estado;
        }

        public bool Equals(Residencia other)
        {
            return other != null && Estado.Equals(other.Estado) && Cidade.Equals(other.Cidade);
        }
    }

    private static void Main(string[] args)
    {
        List<Residencia> ListaResidencia = new List<Residencia>();
        ListaResidencia.Add(new Residencia("São Paulo", "SP"));
        ListaResidencia.Add(new Residencia("Bauru", "SP"));

        var cidade = new Residencia("Bauru", "SP");

        if (ListaResidencia.Any(x => x.Equals(cidade)))
        {
            Console.Write("Já existe uma Residência com esses dados.");
        }
        else
        {
            ListaResidencia.Add(cidade);
        }

        ListaResidencia.Count();

        Console.ReadKey();
    }
  • +1 for the explanation of why concatenating is not a good idea. =)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.