【问题标题】:How to Implement AutoMapper with Generic Repository Pattern如何使用通用存储库模式实现 AutoMapper
【发布时间】:2020-03-31 12:49:49
【问题描述】:

我正在尝试使用包含 BaseController、T 类型的 BaseRepository 的通用存储库模式来实现 AutoMapper。

MapperConfig:

这是在 WebAPI 项目中实现 AutoMapper 的代码的一部分,它在 App_Start() 上调用

 public static class APIMapperConfig
{

    static MapperConfiguration adminConfig;

    public static IMapper adminMapper;

    public static void Configure()
    {
        ConfigureAdminConfiguration();
    }


    public static void ConfigureAdminConfiguration()
    {
        adminConfig = new MapperConfiguration(cfg => {
            cfg.CreateMap<ArticleType, DAL.ArticleType>();
            });

        adminMapper = adminConfig.CreateMapper();

        adminMapper.Map<ArticleType, DAL.ArticleType>(new ArticleType());
    }

}

APIModel(API.ArticleType)

这是 API 用来从客户端接收数据的模型。

public class ArticleType
    {

        public int id { get; set; }

        public String name { get; set; }

        public String displayName { get; set; }

    }

EntityModel(DAL.ArticleType)

这是 EntityFramework 自动生成的模型

public class ArticleType
    {

        public int id { get; set; }

        public String name { get; set; }

        public String displayName { get; set; }

    }

ArticleTypeController:(项目:API)

这是添加 ArticleType 模型时调用的控制器,它是从 T 类型的 BaseController 派生的。

 public class ArticleTypeController : BaseController<ArticleType>
    {

        private IArticleTypeServices article;

        ArticleTypeController()
        {
            this.article = UnityConfig.ResolveObject<IArticleTypeServices>();
        }

    }

BaseController::项目(API)

这是 T 类型的 BaseController,用于为每个模型执行常见任务,如添加、更新等。

    public class BaseController<T> : ApiController
        {
        IBaseRepository<T> rep;

        public BaseController()
        {
            rep= UnityConfig.ResolveObject<IBaseRepository<T>>();
        }
            [HttpPost]
            public void Add(T item)
            {
                rep.Add(item);
            }
        }

BaseRepository:(项目:DALrepository)

BaseController调用这个repository添加模型,这个repository调用Entity framework添加到数据库中。

 public class BaseRepository<T> : IBaseRepository<T> where T : class
    {
        BlogDBContext db;

        public BaseRepository()
        {
            db = UnityConfig.ResolveObject<BlogDBContext>();

        }

        public void Add(T item)
        {

         // Here is the problem

    /*item which is passed from Controller is of type API.ArticleType, and what is expected to pass to entity frmawework is of type DAL.ArticleType.
       Here how do I map between API type and DAL type? It is to be noted that
ArticleType of API and DAL is already mapped inside AutoMapper code at top.*/

            this.Entities.Add(item);
            this.db.SaveChanges();
        }

当我在 Fiddler (http://localhost:xxxxx/api/ArticleType) 中运行它时,它会抛出错误:

实体类型 ArticleType 不是当前上下文模型的一部分

这很明显,因为 API 的 ArticleType 和 DAL 之间没有映射。

BaseRepository Add() 中出现此错误。

我认为这可能与我在 App_Start 中调用 Map 的方式有关。

代码可能看起来很长,但如果我遗漏了什么,请告诉我。

非常感谢您的所有帮助和时间。

【问题讨论】:

  • 只需使用规范数据模型/模式即可。每层定义基本相同的类型只会增加维护。 soapatterns.org/design_patterns/canonical_schema
  • 投反对票???为了什么?
  • @MickyD。不推荐使用实体模式作为商业模式。是..?

标签: c# entity-framework generics asp.net-web-api automapper


【解决方案1】:

配置自动映射器后,您必须在代码中使用它来进行转换。在您的 Add 方法中,您只有有关源类型的信息,但您缺少所需的目标类型。所以你需要某种类型的映射。这必须通过某种Dictionary&lt;Type, Type&gt; 手动完成(AutoMapper 的工作是自动将属性从一种类型映射到另一种类型,而不是找出最适合的目标类型)。通过获得此类信息,您可以创建如下方法:

public void Add(T item)
{
    var destinationType = _mappings[typeof(T)];
    var newEntity = _mapper.Map(item, typeof(T), destinationType);

    this.Entities.Add(newEntity);
    this.db.SaveChanges();
}

// Maybe injected through UnityConfig...
private static _mappings = new Dicionary<Type, Type> {{ typeof(API.ArticleType), typeof(DAL.ArticleType) }};

【讨论】:

  • 感谢您的宝贵时间。考虑到除了通过外部对象提供所需的类型之外别无他法,因为您建议使用字典...这将是一个理想的整体架构吗?我的目的是使代码尽可能通用。请提出建议。
  • 有时,拥有尽可能通用的东西并不理想。当您有特殊情况时,这可能会导致问题。所以我是this approach 的粉丝(也可以观看视频,链接在他的博客中,链接在自述文件中)。你在你的情况下真正做什么取决于你,无论我向你提出什么建议,你都可以有十几个支持或反对它的论据,只是为了把它推向你喜欢的方向。我只能说,您需要这种信息,如何将其输入控制器是您的工作。 ;-)
  • 感谢您的宝贵意见;)
【解决方案2】:

此解决方案有效地将 classDto 模型和 EFDbset 名称传递到存储库。看这里 https://gist.github.com/mcnkbr/f96532254f62a384878f

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-26
    • 2017-07-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多