В настоящее время у меня есть структура наследования, скажем, класс Employee и Manager, наследуемый от абстрактного класса Person. Должен ли я реализовать один репозиторий для каждого конкретного класса или один репозиторий для всей структуры наследования? Лично я считаю более правильным один репозиторий для каждого конкретного класса. Ниже приведена моя реализация этого подхода. Я использую шаблон Data Mapper вместе с репозиторием, но у меня есть некоторые трудности при реализации этого подхода: некоторые методы я не знаю, куда поместить, кроме класса Data Mapper, но очень неудобно помещать туда также
public enum PersonType
{
Unknown = 0,
Employee = 1,
Manager = 2
}
public abstract class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public PersonType Type { get; set; }
//Omitted properties and methods
}
public class Employee : Person
{
public string EmployeeNo { get; set; }
//Omitted properties and methods
}
public class Manager : Person
{
public string ManagerNo { get; set; }
//Omitted properties and methods
}
Ниже приведены классы картографов:
public interface IMapper
{
bool CanMap(PersonType type);
Person MapFrom(DataRow dataRow);
//This method is awkward to put here
SqlCommand CreateUpdateCommandFrom(Person person);
}
public abstract class MapperBase : IMapper
{
public abstract bool CanMap(PersonType type);
public abstract Person MapFrom(DataRow dataRow);
public abstract SqlCommand CreateUpdateCommandFrom(Person person);
protected T MapCommonPropertiesFrom<T>(DataRow dataRow) where T : Person, new()
{
return new T
{
//Populate common properties like id, name, age
};
}
}
public class EmployeeMapper : MapperBase
{
public override bool CanMap(PersonType type)
{
return type == PersonType.Employee;
}
public override Person MapFrom(DataRow dataRow)
{
Employee employee = MapCommonPropertiesFrom<Employee>(dataRow);
//Populate employee properties
return employee;
}
public override SqlCommand CreateUpdateCommandFrom(Person person)
{
SqlCommand updateCmd = new SqlCommand();
//Set parameters for updateCmd from person properties
return updateCmd;
}
}
//Similar class for ManagerMapper
Ниже приведен класс регистрации для поиска класса картографа.
public static class MapperRegistry
{
private static List<IMapper> _Mappers = RegisterMappers();
private static List<IMapper> RegisterMappers()
{
return new List<IMapper>
{
new EmployeeMapper()
//ManagerMapper
};
}
public static IMapper FindMapperFor(PersonType type)
{
foreach (IMapper eachMapper in _Mappers)
{
if (eachMapper.CanMap(type))
{
return eachMapper;
}
}
throw new ArgumentException(string.Format("Cannot find mapper for {0}", type));
}
}
И последний класс - это класс репозитория
public class PersonRepository
{
public Person FindBy(int id)
{
//Execute query command in db, get datatable back, store each person
DataTable returnedData = ExecuteQueryCommand(id);
PersonType type = int.Parse(returnedData.Rows[0], "Id");
IMapper mapper = MapperRegistry.FindMapperFor(type);
return mapper.MapFrom(returnedData.Rows[0]);
}
private DataTable ExecuteQueryCommand(int id)
{
//Execute query command in db
return new DataTable();
}
public void Update<T>(T person) where T : Person
{
IMapper mapper = MapperRegistry.FindMapperFor(person.Type);
SqlCommand updateCmd = mapper.CreateUpdateCommandFrom(person);
//Execute update command
}
}
Я считаю неправильным то, что CreateUpdateCommandFrom(), в настоящее время помещенный в класс Mapper, по праву должен быть помещен в класс репозитория, но в общем классе репозитория мы не знаем конкретных свойств дочернего класса, таких как EmployeeNo в классе Employee и ManagerNo в классе Manager, поэтому мы не можем создать общий SqlCommand в репозитории
Есть ли лучший подход? Большое спасибо