中文字幕精品亚洲无线码二区,国产黄a三级三级三级看三级,亚洲七七久久桃花影院,丰满少妇被猛烈进入,国产小视频在线观看网站

PocoEmit遙(yao)遙(yao)領(ling)先于(yu)AutoMapper之打通充血模型的任督二脈

一、充血模型和失血模型

1. 充血模型的優勢

  • 充血模型更加OOP
  • 充血模型代碼可讀性更好

1.1 充血模型偽代碼

var messageDto = controller.ReadDto();
var message = messageDto.ToEntity();
message.Save();

1.2 失血模型偽代碼

var messageDto = controller.ReadDto();
var message = messageDto.ToEntity();
var messageService = controller.GetMessageService();
messageService.Save(message);

2. 充血模型愛你不容易

  • 大部分程序員都知道充血模型好,想實現卻很難
  • 大部分業務邏輯都需要依賴外部服務
  • 充血模型需要用到外部服務,又不想依賴外部服務的具體實現
  • 很容易想到使用IOC的依賴注入來解決
  • 我們給DTO注入服務還行,因為IOC參與了controller過程
  • 當DTO發生轉化時,新增的服務IOC還是有點力不從心
  • 沒法引用外部服務的充血模型氣血不通,業務表達能力大大下降
  • 這也是大部分人棄用充血模型的主要原因,不好用還不如不用
  • 這個任督二脈PocoEmit可以幫你打通

二、首先來個Case演示一下

  • Dto轉化為實體
  • 但是實體有更多邏輯依賴外部服務,這些外部服務Dto不見得提供的了
  • 這就需要注入
  • PocoEmit支持構造函數參數注入和屬性注入
  • IMapper對象是默認支持注入的服務

1. Entity比Dto多出來的Mapper可以注入

class MessageDto
{
    public string Message { get; set; }
}
class MessageEntity
{
    public IMapper Mapper { get; set; }
    public string Message { get; set; }
}

2. 轉化并注入的代碼

var mapper = Mapper.Create();
var dto = new MessageDto { Message = "Hello UseMapper" };
MessageEntity message = mapper.Convert<MessageDto, MessageEntity>(dto);
Assert.NotNull(message.Mapper);

三、再演示注入自定義的服務

1. UserDomain比Dto多出來的Repository可以注入

class UserDTO
{
    public int Id { get; set; }
    public string Name { get; set; }
}
class UserDomain(UserRepository repository, int id, string name)
{
    private readonly UserRepository _repository = repository;
    public UserRepository Repository
        => _repository;
    public int Id { get; } = id;
    public string Name { get; } = name;
    // ...
}
class UserRepository
{
    void Add(UserDomain user) { }
    void Update(UserDomain entity) { }
    void Remove(UserDomain entity) { }
    public static readonly UserRepository Instance = new();
}

2. 注冊、轉化并注入的代碼

  • 通過UseDefault可以注入服務
IMapper mapper = Mapper.Create()
    .UseDefault(UserRepository.Instance);
var dto = new UserDTO { Id = 1, Name = "Jxj" };
UserDomain user = mapper.Convert<UserDTO, UserDomain>(dto);
Assert.NotNull(user.Repository);

四、注入IOC容器的Case

  • 注入IOC容器需要安裝nuget包PocoEmit.ServiceProvider

1. 包含IOC容器的實體

class UserWithServiceProvider
{
    public int Id { get; set; }
    public string Name { get; set; }
    public IServiceProvider ServiceProvider { get; set; }
}

2. 注冊、轉化并注入的代碼

  • UseSingleton是把容器作為唯一容器注入
  • UseScope是使用當前Scope子容器
  • UseContext是在Mvc下,使用當前HttpContext的RequestServices子容器
var services = new ServiceCollection();
var serviceProvider = services.BuildServiceProvider();
var mapper = Mapper.Create();
mapper.UseSingleton(serviceProvider);
var dto = new UserDTO { Id = 1, Name = "Jxj" };
UserWithServiceProvider user = mapper.Convert<UserDTO, UserWithServiceProvider>(dto);
Assert.NotNull(user.ServiceProvider);

五、當然還可以注入容器內的服務

1. UserDomain多出來的Repository需要注入

  • 這次我們用IOC來管理Repository
  • 這樣才能更好的利用依賴注入
  • Repository可能還會依賴其他的服務
  • 手動維護服務對象可能會很麻煩,IOC容器擅長維護這些復雜關系
    class UserDomain(UserRepository repository, int id, string name)
    {
        private readonly UserRepository _repository = repository;
        public UserRepository Repository
            => _repository;
        public int Id { get; } = id;
        public string Name { get; } = name;
        // ...
    }
    class UserRepository
    {
        void Add(UserDomain user) { }
        void Update(UserDomain entity) { }
        void Remove(UserDomain entity) { }
    }

2. 注冊、轉化并注入的代碼

  • 通過UseScope注入IOC容器
  • 通過UseDefault告知這個類型從IOC容器中注入
var services = new ServiceCollection()
    .AddScoped<UserRepository>();
var serviceProvider = services.BuildServiceProvider();
var mapper = Mapper.Create();
mapper.UseScope(serviceProvider)
     .UseDefault<UserRepository>();
var dto = new UserDTO { Id = 1, Name = "Jxj" };
UserDomain user = mapper.Convert<UserDTO, UserDomain>(dto);
Assert.NotNull(user.Repository);

六、支持IOC容器的特性

  • 支持FromKeyedServices
  • 支持FromServices

1. FromKeyedServices標記注入點和服務鍵

class UserDomain1([FromKeyedServices("User1")]UserRepository repository, int id, string name)
    : UserDomain(repository, id, name)
{
}
class UserDomain2([FromKeyedServices("User2")] UserRepository repository, int id, string name)
    : UserDomain(repository, id, name)
{
}
class UserDomain(UserRepository repository, int id, string name)
{
    private readonly UserRepository _repository = repository;
    public UserRepository Repository
        => _repository;
    public int Id { get; } = id;
    public string Name { get; } = name;
    // ...
}
class UserRepository(string tableName)
{
    private readonly string _tableName = tableName;
    public string TableName 
        => _tableName;
    void Add(UserDomain user) { }
    void Update(UserDomain entity) { }
    void Remove(UserDomain entity) { }
}

2. 注冊、轉化并注入的代碼

  • 由于識別出FromKeyedServices,就不需要UseDefault
  • 這樣簡潔又優雅
string table1 = "User1";
string table2 = "User2";
var services = new ServiceCollection()
    .AddKeyedScoped(table1, (_, _) => new UserRepository(table1))
    .AddKeyedScoped(table2, (_, _) => new UserRepository(table2));
var serviceProvider = services.BuildServiceProvider();
var mapper = Mapper.Create();
mapper.UseScope(serviceProvider);
var dto = new UserDTO { Id = 1, Name = "Jxj" };
UserDomain user = mapper.Convert<UserDTO, UserDomain1>(dto);
Assert.NotNull(user.Repository);
UserDomain user2 = mapper.Convert<UserDTO, UserDomain2>(dto);
Assert.NotNull(user2.Repository);

七、競品類似的功能

1. AutoMapper不支持

  • AutoMapper的NullSubstitute用來指定源屬性為null時的默認值
  • 用AutoMapper實現類似功能需要復雜的自定義IValueResolver來實現
  • PocoEmit在源無法匹配或源字段為null都可能觸發依賴注入

2. EF有類似功能

八、總結

1. OOM映射需要依賴注入

  • DTO、實體、領域模型如果有業務邏輯就需要依賴外部服務
  • 支持按類型注入,也支持按指定的參數或屬性注入
  • 支持FromKeyedServices和FromServices
  • 需要外部服務就需要依賴注入

2. PocoEmit的依賴注入助力程序分層架構

  • 依賴注入的加持每一層想調用啥就調用啥
  • 同時也讓每一層更好的劃分讓調用啥,不讓調用啥更容易控制
  • 同時也讓業務需要劃分多少層就劃分多層變得簡單

3. IOC容器使用需要注意

  • 簡單作業單容器,使用UseSingleton即可
  • 多線程需要使用UseScope
  • Mvc(含WebApi)邏輯處理使用UseContext
  • UseContext需要引用nuget包PocoEmit.Mvc
  • 如果是Mvc異步處理或Quartz類似作業不要用UseContext
  • 就怕異步中獲取到了HttpContext,但執行中途被釋放了,后面就可能異常了

另外源碼托管地址: ,歡迎大家直接查看源碼。
gitee同步(bu)更新(xin):

如果大(da)家喜歡請動動您發(fa)財的小(xiao)手手幫忙點一(yi)下Star,謝(xie)謝(xie)!!!

posted on 2025-10-04 09:38  xiangji  閱讀(242)  評論(0)    收藏  舉報

導航