Любые советы о том, как избежать дублирования кода в этой абстракции?
Поэтому я создаю приложение с использованием Entity Framework поверх SQL Compact Edition. Мне не понравилась идея использовать Entites в качестве моих бизнес-объектов, поэтому я строил слой (я назвал его слоем ObjectModel, вероятно, не самая лучшая терминология), который будет брать мои простые объекты, использовать их заполнить и сохранить сущности. А также наоборот - принимать энтузиасты, заполнять POCO для использования в качестве бизнес-объекта
Допустим, у меня есть объект POCO с именем Customer,
public class Customer:ICustomer
{
#region ICustomer Members
public System.Guid id {get;set;}
public string Forename {get;set;}
public string Surname { get; set; }
#endregion
}
И я хочу заполнить это, используя мой слой ObjectModel. Я в настоящее время делаю это...
OM_Customer<ICustomer,Entity.Customer> customerLayer = new OM_Agent<ICustomer,Entity.Customer>();
ICustomer businessObject = customerLayer.GetById(new Guid("4a75d5a5-6f5a-464f-b4b3-e7807806f1a9"));
Класс OM_Customer наследуется от ObjectModelBase, который ниже.
public abstract class ObjectModelBase<BllClass, EntityClass>
{
public DataStoreEntities1 db;
public EntityClass _dataObject;
public string setName;
#region POCO-ORM Mapping Functions
public EntityClass MapBLLToEntity(BllClass bllObject)
{
Mapper.CreateMap<BllClass, EntityClass>();
return Mapper.Map<BllClass, EntityClass>(bllObject);
}
public BllClass MapEntityToBLL(EntityClass entityObject)
{
Mapper.CreateMap<EntityClass, BllClass>();
return Mapper.Map<EntityClass, BllClass>(entityObject);
}
#endregion
public void Save(BllClass toAdd)
{
_dataObject = MapBLLToEntity(toAdd);
using (db = new DataStoreEntities1())
{
db.AddObject(setName, _dataObject);
db.SaveChanges();
}
}
public BllClass GetById(Guid id)
{
using (db = new DataStoreEntities1())
{
EntityClass result = (EntityClass)((object)(from c in db.CustomerSet where c.id == id select c).First());
return MapEntityToBLL(result);
}
}
}
Проблема здесь заключается в методе GetById. Метод Save может использоваться подклассами в порядке, поскольку все контексты объектов Entity Framework имеют метод AddObject().
Тем не менее, я хочу иметь общий метод getById, так как все мои сущности будут иметь свойство с именем id (также в db, являющемся первичным ключом). Проблема в том, что здесь linq...
ModelClass result = (ModelClass)((object)(from c in db.CustomerSet where c.id == id select c).First());
специфично для db.CustomerSet. Я хочу, чтобы этот абстрактный класс предоставлял общий CRUD/Paging/'Collection Retrieval' для всех моих сущностей, но без повторяющихся нажатий клавиш, однако, этот простой метод GetById заставил меня обратиться за помощью.
Актуальные идеи:
- чтобы мой get by Id использовал Entity SQL, где у меня был бы больший контроль над созданием строки запроса.
- удалите структуру сущности и linq, так как для полной абстракции может потребоваться слишком много времени.
Буду признателен за любую информацию о том, как сообщество SO будет решать вышеуказанное.
1 ответ
Во-первых, я хотел бы начать с вопроса, почему вы чувствуете, что использование EF-сущностей в качестве ваших бизнес-сущностей обязательно было бы плохо? Я сделал это в ряде проектов, и мне еще предстоит столкнуться с серьезными проблемами, которые я не могу преодолеть.
Сказав это, если вы действительно чувствуете, что у вас есть веская причина для разделения двух, вот один из вариантов.
Вы можете использовать делегата, чтобы внедрить конкретный объект набора сущностей для запроса и другой для селектора для ключа - это может позволить производным указывать только свою семантику хранения. Итак, ваш код будет выглядеть так:
public abstract class ObjectModelBase<BllClass, EntityClass>
{
// ... same basic code here...
// supplied by your derivatives...
protected abstract Func<IQueryable<EntityClass>> GetEntitySet { get; };
protected abstract Func<Guid,Func<EntityClass,bool>> KeySelector { get; }
public BllClass GetById(Guid id)
{
using (db = new DataStoreEntities1())
{
EntityClass result = (EntityClass)((object)
GetEntitySet()
.Where( KeySelector( id ) )
.First();
return MapEntityToBLL(result);
}
}
}
public class OM_Customer : ObjectModelBase<ICustomer,Entity.Customer>
{
protected abstract Func<IQueryable<Entity.Customer>> GetEntitySet
{
get { return db.CustomerSet; }
}
protected abstract Func<Guid,Func<Entity.Customer,bool>> KeySelector
{
get { return (g => (e => e.Id == g)); }
}
}