Я пытаюсь стать хорошим гражданином в программировании, узнав больше о Dependency Injection / IoC и других передовых методах. Для этого у меня есть проект, в котором я пытаюсь сделать правильный выбор и спроектировать все «правильным» образом, что бы это ни значило. Ninject, Moq и ASP.NET MVC помогают в тестировании и выводе приложения на улицу.
Однако у меня есть вопрос о том, как разработать базовый класс сущности для объектов, из которых состоит мое приложение. У меня есть простая библиотека классов, на которой построено веб-приложение. Эта библиотека предоставляет интерфейс IRepository, а реализация по умолчанию (та, которую использует приложение) использует Linq-to-SQL под оболочкой (DataContext и т. Д. Не предоставляется веб-приложению) и просто содержит способы извлечения этих объектов. Хранилище в основном выглядит так (упрощенно):
public interface IRepository
{
IEnumerable<T> FindAll<T>() where T : Entity
T Get<T>(int id) where T : Entity
}
Реализация по умолчанию использует метод GetTable () в DataContext для предоставления правильных данных.
Однако для этого необходимо, чтобы базовый класс "Entity" имел некоторые функции. Достаточно легко заставить мои объекты наследоваться от него, создав частичный класс с тем же именем, что и сопоставленный объект, который мне дает Linq-to-SQL, но каков «правильный» способ сделать это?
Например, вышеприведенный интерфейс имеет функцию для получения сущности по ее идентификатору - у всех различных классов, производных от сущности, действительно есть поле «id» типа int (сопоставленное с первичным ключом их соответствующего таблицы), но как я могу указать это таким образом, чтобы я мог реализовать IRepository, как это?
public class ConcreteRepository : IRepository
{
private SomeDataContext db = new SomeDataContext();
public IEnumerable<T> FindAll<T>() where T : Entity
{
return db.GetTable<T>().ToList();
}
public T Get(int id) where T : Entity
{
return db.GetTable<T>().Where(ent => ent.id == id).FirstOrDefault();
}
}
Я делаю это из памяти на компьютере без компилятора, так что простите за любые ошибки, надеюсь, вы поймете мое намерение.
Трюк здесь, конечно, в том, что для его компиляции необходимо точно знать, что Entity обещает, что каждый, кто его получает, имеет поле id.
И я могу создать абстрактное поле или обычное поле, которое «скрыто» полем id, которое Linq-to-SQL вставляет в сгенерированные классы.
Но все это похоже на чит и даже выдает предупреждения компилятора.
Должно ли "Entity" действительно быть "IEntity" (вместо интерфейса), и я должен попытаться определить поле id таким образом, чтобы Linq-to-SQL выполнял? Это также упростит указание других интерфейсов, которые необходимо реализовать разработчикам сущностей.
Или «Entity» должен быть абстрактным базовым классом с абстрактным полем id, и должен ли он также реализовывать необходимые интерфейсы абстрактным образом, чтобы другие могли его переопределить?
Я недостаточно хорошо знаю C #, чтобы увидеть элегантное решение, поэтому я хотел бы услышать мнение более опытных разработчиков систем, имеющих некоторый опыт базового класса.
Спасибо!
РЕДАКТИРОВАТЬ 10 апреля:
Я вижу, что упустил что-то важное здесь. В моем IRepository есть две конкретные реализации - одна «настоящая», использующая LINQ to SQL, другая - InMemoryRepository, которая сейчас использует только List, который используется для модульного тестирования и т. Д.
Оба добавленных решения будут работать для одной из этих ситуаций, а не для другой. Поэтому, если возможно, мне нужен способ определить, что все, что наследуется от Entity, будет иметь свойство «id», и что это будет работать с LINQ to SQL DataContext без «мошенничества».