I ha trovato la tua domanda in cerca di una soluzione alla stessa domanda. Ecco una soluzione che sto provando, vedere se soddisfa le vostre esigenze:
In primo luogo, tutti i miei pocos derivano da questa classe astratta:
public abstract class BasePOCO <T> : IEquatable<T> where T : class
{
private readonly Guid _guid = Guid.NewGuid();
#region IEquatable<T> Members
public abstract bool Equals(T other);
#endregion
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != typeof (T))
{
return false;
}
return Equals((T)obj);
}
public override int GetHashCode()
{
return _guid.GetHashCode();
}
}
ho creato un campo di sola lettura Guid che io sono utilizzando l'override GetHashCode(). Ciò assicurerà che se dovessi inserire il POCO derivato in un dizionario o qualcos'altro che utilizza l'hash, non lo farei orfano se avessi chiamato un .SaveChanges() nel frattempo e il campo ID fosse aggiornato dalla classe base è l'unica parte che non sono sicuro è completamente corretta, o se è meglio di Base.GetHashCode()?. Ho astratto il metodo Equals (T other) per garantire che le classi di implementazione dovessero implementarlo in modo significativo, molto probabilmente con il campo ID. Ho inserito l'override di Equals (object obj) in questa classe base perché probabilmente sarebbe lo stesso per tutte le classi derivate.
questo sarebbe un implementazione della classe astratta:
public class Species : BasePOCO<Species>
{
public int ID { get; set; }
public string LegacyCode { get; set; }
public string Name { get; set; }
public override bool Equals(Species other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return ID != 0 &&
ID == other.ID &&
LegacyCode == other.LegacyCode &&
Name == other.Name;
}
}
La proprietà ID è impostato come chiave primaria nel database e EF sa che. L'ID è 0 su un oggetto appena creato, quindi viene impostato su un intero positivo univoco su .SaveChanges(). Quindi nel metodo Equals override (Species other), gli oggetti nulli non sono ovviamente uguali, ovviamente lo stesso riferimento è, quindi dobbiamo solo verificare se l'ID == 0. Se lo è, diremo che due oggetti dello stesso tipo che entrambi hanno ID 0 non sono uguali. Altrimenti, diremo che sono uguali se le loro proprietà sono tutte uguali.
Penso che questo copra tutte le situazioni rilevanti, ma per favore inseriscimi se non sono corretto. Spero che questo ti aiuti.
=== Modifica 1
Stavo pensando il mio GetHashCode() non era giusto, e ho guardato questo https://stackoverflow.com/a/371348/213169 risposta per quanto riguarda il soggetto.L'implementazione sopra violerebbe il vincolo che gli oggetti che restituiscono Equals() == true devono avere lo stesso hashcode.
Qui è la mia seconda pugnalata a lui:
public abstract class BasePOCO <T> : IEquatable<T> where T : class
{
#region IEquatable<T> Members
public abstract bool Equals(T other);
#endregion
public abstract override bool Equals(object obj);
public abstract override int GetHashCode();
}
e l'implementazione:
public class Species : BasePOCO<Species>
{
public int ID { get; set; }
public string LegacyCode { get; set; }
public string Name { get; set; }
public override bool Equals(Species other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return ID != 0 &&
ID == other.ID &&
LegacyCode == other.LegacyCode &&
Name == other.Name;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
return Equals(obj as Species);
}
public override int GetHashCode()
{
unchecked
{
return ((LegacyCode != null ? LegacyCode.GetHashCode() : 0) * 397)^
(Name != null ? Name.GetHashCode() : 0);
}
}
public static bool operator ==(Species left, Species right)
{
return Equals(left, right);
}
public static bool operator !=(Species left, Species right)
{
return !Equals(left, right);
}
}
Così mi sono liberato del GUID nella classe base e si è trasferito GetHashCode alla realizzazione. Ho usato l'implementazione di GetHashCode di Resharper con tutte le proprietà tranne l'ID, dato che l'ID potrebbe cambiare (non voglio orfani). Questo soddisferà il vincolo sull'eguaglianza nella risposta collegata sopra.
Perché i tuoi oggetti hanno un ID 0? Perché non come JomTois mostra nel suo esempio di codice direttamente assegnare un Guid a un campo ID/Proprietà. Questa è una base ideale per la tua IEquatable che menzioni tu stesso. Anche TomTom indica i metodi di assegnazione di un intervallo di identificazione per ogni cliente o utilizzando -1, -2 e -3 come ID temporanei, queste "soluzioni" sembrano complemento delle cose. Al momento della costruzione si genera una nuova guida e sono in attività. O mi manca qualcosa? –
@YoupTube: i numeri interi non possono essere senza valore. Inoltre, gli interi sono a 32 bit mentre i GUID sono a 128 bit. Ciò significa che SQL Server può contenere fino a 4 ID quanti in memoria utilizzando un numero intero (chiave per le prestazioni quando si eseguono i join). –
Ah, capisco. Ma hai un sacco di dati, traffico, join e hai bisogno di prestazioni altissime? È sempre un compromesso ... lo so. Ma usare guid non dovrebbe essere un grosso problema. E poi puoi dimenticare tutti i problemi complessi che hai a causa dell'uso di interi. –