I натолкнулся на ваш вопрос в поисках решения одного и того же вопроса. Вот решение, что я пробуя, увидеть, если она соответствует вашим потребностям:
Во-первых, все мои POCO которые вытекают из этого абстрактного класса:
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();
}
}
Я создал только для чтения поле Guid что я используя переопределение GetHashCode(). Это гарантирует, что если бы я поставил производный POCO в словарь или что-то еще, использующее хеш, я бы не стал его сиротой, если бы я вызывал .SaveChanges() в промежутке времени, а поле идентификатора обновлялось базовым классом это одна часть, я не уверен, что это абсолютно правильно, или если она лучше, чем просто Base.GetHashCode()?. Я абстрагировал метод Equals (T другой), чтобы гарантировать, что классы реализации должны были реализовать его каким-либо значимым образом, скорее всего, с полем ID. Я поместил переопределение Equals (object obj) в этот базовый класс, потому что он, вероятно, будет одинаковым для всех производных классов.
Это будет реализация абстрактного класса:
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;
}
}
Свойство ID устанавливается в качестве первичного ключа в базе данных и EF знает. Идентификатор равен 0 на вновь созданных объектах, а затем устанавливается на уникальное положительное целое на .SaveChanges(). Таким образом, в переопределенном методе Equals (Species other) нулевые объекты, очевидно, не равны, одинаковые ссылки, очевидно, есть, тогда нам нужно только проверить, равен ли ID == 0. Если это так, мы скажем, что два объекта одного типа что оба идентификатора 0 не равны. В противном случае мы скажем, что они равны, если их свойства одинаковы.
Я думаю, что это охватывает все соответствующие ситуации, но, пожалуйста, звоните, если я ошибаюсь. Надеюсь это поможет.
=== Edit 1
Я думал мой GetHashCode() не был прав, и я смотрел на это https://stackoverflow.com/a/371348/213169 ответ относительно предмета.Вышеприведенная реализация нарушила бы ограничение, что объекты, возвращающие Equals() == true, должны иметь один и тот же хэш-код.
Вот мой второй удар в нем:
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();
}
И реализация:
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);
}
}
Так я избавилась от Guid в базовом классе и переехал GetHashCode к реализации. Я использовал Resharper реализацию GetHashCode со всеми свойствами, кроме ID, так как ID мог измениться (не хотите сирот). Это встретит ограничение на равенство в связанном ответе выше.
Почему у ваших объектов есть идентификатор 0? Почему не так, как показывает JomTois в своем примере кода, напрямую назначьте Guid в поле ID/Property. Это идеальная основа для вашего IEquatable, о котором вы упоминаете. Также TomTom указывает методы присвоения идентификатора Range для каждого клиента или использования -1, -2 и -3 в качестве временного идентификатора, эти «решения», похоже, верят в детали. После строительства вы создаете новый Guid и находитесь в бизнесе. Или мне что-то не хватает? –
@YoupTube: Целые числа не могут быть бесполезными. Кроме того, целые числа являются 32-битными, а идентификаторы GUID - 128 бит. Это означает, что SQL Server может вместить в 4 раза больше идентификаторов в памяти, используя Integer (ключ к производительности при выполнении объединений). –
А, я понимаю. Но есть ли у вас множество данных, трафика, соединений и необходимость в сверхвысокой производительности? Это всегда компромисс ... Я знаю. Но использование guid's не должно быть большой проблемой. И тогда вы можете забыть обо всех сложных проблемах, связанных с использованием целых чисел. –