【问题标题】:Any tips on avoiding code Duplication on this abstraction?关于避免此抽象上的代码重复的任何提示?
【发布时间】:2010-11-08 13:01:06
【问题描述】:

所以我在 SQL Compact Edition 之上使用实体框架构建了一个应用程序。我不喜欢使用实体作为我的业务对象的想法,所以我一直在构建一个层(我称它为 ObjectModel 层,可能不是最好的术语)在这两者之间将采用我的普通对象,使用它们填充和保存实体。反之亦然 - 获取实体,填充 POCO 以用作业务对象


假设我有一个名为 Customer 的 POCO 对象,

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 方法可以被子类很好地使用,因为所有实体框架对象上下文都有 AddObject() 方法。

但是,我希望有一个通用的 getById 方法,因为我所有的实体都有一个名为 id 的属性(在数据库中也是主键)。问题是这里的 linq...

ModelClass result = (ModelClass)((object)(from c in  db.CustomerSet  where c.id == id select c).First());

特定于 db.CustomerSet。我希望这个抽象类为我的所有实体提供通用的 CRUD/Paging/'Collection Retrieval',但是没有重复的击键,但是这个简单的 GetById 方法促使我寻求帮助。

当前想法:

  • 让我通过 Id 获得使用实体 SQL,我可以更好地控制构建查询字符串。
  • 废弃实体框架和 linq,因为它可能太耗时而无法完全抽象。

对于 SO 社区将如何解决上述问题的任何建议都将不胜感激。

【问题讨论】:

  • 您是在构建 Web 应用还是 Windows 应用?
  • 这是一个 Windows 应用程序,但它也可以很容易地成为 web 应用程序的代码,相关性?

标签: c# entity-framework abstract-class data-access-layer


【解决方案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)); }
    }
}

【讨论】:

  • 非常感谢。我觉得有必要将两者分开,原因有两个。 a) 促进可测试性 b) 如果我愿意,将来可以更改数据访问解决方案,而不必触及我的任何业务逻辑类。再次为您抽出时间提供帮助而欢呼。
猜你喜欢
  • 1970-01-01
  • 2017-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-19
  • 2023-03-22
  • 1970-01-01
相关资源
最近更新 更多