Другая альтернатива, если вы предпочитаете не насмехаться над классами сущностей, - это установить закрытый / защищенный идентификатор с помощью отражения.
Да, я знаю, что на это обычно не обращают особого внимания, и его часто называют признаком плохого дизайна.Но в этом случае наличие защищенного идентификатора на ваших объектах NHibernate является стандартной парадигмой, поэтому это кажется вполне разумным решением.
Мы можем попытаться реализовать его как минимум.В моем случае 95% моих сущностей все используют один Guid в качестве уникального идентификатора, и лишь немногие используют целое число.Поэтому наши классы сущностей обычно реализуют очень простой HasID
интерфейс:
public interface IHasID<T>
{
T ID { get; }
}
В реальном классе сущностей мы можем реализовать его следующим образом:
public class User : IHasID<Guid>
{
Guid ID { get; protected set; }
}
Этот идентификатор сопоставлен сNHibernate в качестве первичного ключа обычным способом.
Для установки этого в наших модульных тестах мы можем использовать этот интерфейс для предоставления удобного метода расширения:
public static T WithID<T, K>(this T o, K id) where T : class, IHasID<K>
{
if (o == null) return o;
o.GetType().InvokeMember("ID", BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, o, new object[] { id });
return o;
}
Мы неДля этого необходим интерфейс HasID, но это означает, что мы можем пропустить немного лишнего кода - например, нам не нужно проверять, поддерживается ли идентификатор на самом деле.
Метод расширениятакже возвращает исходный объект, поэтому при использовании я обычно просто цепляю его в конце конструктора:
var testUser = new User("Test User").WithID(new Guid("DC1BA89C-9DB2-48ac-8CE2-E61360970DF7"));
Или на самом деле, поскольку для Guids мне все равно, какой идентификатор на самом деле, у меня есть другойметод расширения:
public static T WithNewGuid<T>(this T o) where T : class, IHasID<Guid>
{
if (o == null) return o;
o.GetType().InvokeMember("ID", BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, o, new object[] { Guid.NewGuid() });
return o;
}
и в использовании:
var testUser = new User("Test User").WithNewGuid();