<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Util應(yīng)用框架基礎(chǔ)(二) - 對(duì)象到對(duì)象映射(AutoMapper)

      本節(jié)介紹Util應(yīng)用框架相似對(duì)象之間的轉(zhuǎn)換方法.

      文章分為多個(gè)小節(jié),如果對(duì)設(shè)計(jì)原理不感興趣,只需閱讀基礎(chǔ)用法部分即可.

      概述

      現(xiàn)代化分層架構(gòu),普遍采用了構(gòu)造塊DTO(數(shù)據(jù)傳輸對(duì)象).

      DTO是一種參數(shù)對(duì)象,當(dāng)Web API接收到請(qǐng)求,請(qǐng)求參數(shù)被裝載到DTO對(duì)象中.

      我們需要把 DTO 對(duì)象轉(zhuǎn)換成實(shí)體,才能保存到數(shù)據(jù)庫.

      當(dāng)返回響應(yīng)消息時(shí),需要把實(shí)體轉(zhuǎn)換成DTO,再傳回客戶端.

      對(duì)于簡單的系統(tǒng),DTO和實(shí)體非常相似,它們可能包含大量相同的屬性.

      除此之外,還有很多場景也需要轉(zhuǎn)換相似對(duì)象.

      下面的例子定義了學(xué)生實(shí)體和學(xué)生參數(shù)DTO.

      它們包含兩個(gè)相同的屬性.

      StudentService 是一個(gè)應(yīng)用服務(wù).

      CreateAsync 方法創(chuàng)建學(xué)生,把DTO對(duì)象手工賦值轉(zhuǎn)換為學(xué)生實(shí)體,并添加到數(shù)據(jù)庫.

      GetByIdAsync 方法通過ID獲取學(xué)生實(shí)體,并手工賦值轉(zhuǎn)換為學(xué)生DTO.

      /// <summary>
      /// 學(xué)生
      /// </summary>
      public class Student : AggregateRoot<Student> {
          /// <summary>
          /// 初始化學(xué)生
          /// </summary>
          public Student() : this( Guid.Empty ) {
          }
      
          /// <summary>
          /// 初始化學(xué)生
          /// </summary>
          /// <param name="id">學(xué)生標(biāo)識(shí)</param>
          public Student( Guid id ) : base( id ) {
          }
      
          /// <summary>
          /// 姓名
          ///</summary>
          public string Name { get; set; }
      
          /// <summary>
          /// 出生日期
          ///</summary>
          public DateTime? Birthday { get; set; }
      }
      
      /// <summary>
      /// 學(xué)生參數(shù)
      /// </summary>
      public class StudentDto : DtoBase {
          /// <summary>
          /// 姓名
          ///</summary>
          public string Name { get; set; }
          /// <summary>
          /// 出生日期
          ///</summary>
          public DateTime? Birthday { get; set; }
      }
      
      /// <summary>
      /// 學(xué)生服務(wù)
      /// </summary>
      public class StudentService {
          /// <summary>
          /// 工作單元
          /// </summary>
          private IDemoUnitOfWork _demoUnitOfWork;
          /// <summary>
          /// 學(xué)生倉儲(chǔ)
          /// </summary>
          private IStudentRepository _repository;
      
          /// <summary>
          /// 初始化學(xué)生服務(wù)
          /// </summary>
          /// <param name="unitOfWork">工作單元</param>
          /// <param name="repository">學(xué)生倉儲(chǔ)</param>
          public StudentService( IDemoUnitOfWork unitOfWork, IStudentRepository repository ) {
              _demoUnitOfWork = unitOfWork;
              _repository = repository;
          }
      
          /// <summary>
          /// 創(chuàng)建學(xué)生
          /// </summary>
          /// <param name="dto">學(xué)生參數(shù)</param>
          public async Task CreateAsync( StudentDto dto ) {
              var entity = new Student { Name = dto.Name, Birthday = dto.Birthday };
              await _repository.AddAsync( entity );
              await _demoUnitOfWork.CommitAsync();
          }
      
          /// <summary>
          /// 獲取學(xué)生
          /// </summary>
          /// <param name="id">學(xué)生標(biāo)識(shí)</param>
          public async Task<StudentDto> GetByIdAsync( Guid id ) {
              var entity = await _repository.FindByIdAsync( id );
              return new StudentDto { Name = entity.Name, Birthday = entity.Birthday };
          }
      }
      

      學(xué)生范例只有兩個(gè)屬性,手工轉(zhuǎn)換工作量并不大.

      但真實(shí)的應(yīng)用每個(gè)對(duì)象可能包含數(shù)十個(gè)屬性,使用手工賦值的方式轉(zhuǎn)換,效率低下且容易出錯(cuò).

      我們需要一種自動(dòng)化的轉(zhuǎn)換手段.

      對(duì)象到對(duì)象映射框架 AutoMapper

      Util應(yīng)用框架使用 AutoMapper ,它是 .Net 最流行的對(duì)象間映射框架.

      AutoMapper 可以自動(dòng)轉(zhuǎn)換相同名稱和類型的屬性,同時(shí)支持一些約定轉(zhuǎn)換方式.

      基礎(chǔ)用法

      引用Nuget包

      Nuget包名: Util.ObjectMapping.AutoMapper.

      通常不需要手工引用它.

      MapTo 擴(kuò)展方法

      Util應(yīng)用框架在根對(duì)象 object 擴(kuò)展了 MapTo 方法,你可以在任何對(duì)象上調(diào)用 MapTo 進(jìn)行對(duì)象轉(zhuǎn)換.

      擴(kuò)展方法需要引用命名空間, MapTo 擴(kuò)展方法在 Util 命名空間.

      using Util;

      有兩種調(diào)用形式.

      • 調(diào)用形式1: 源對(duì)象實(shí)例.MapTo<目標(biāo)類型>()

        • 范例: 這里的源對(duì)象實(shí)例是學(xué)生參數(shù) dto,目標(biāo)類型是 Student,返回 Student 對(duì)象實(shí)例.
          /// <summary>
          /// 創(chuàng)建學(xué)生
          /// </summary>
          /// <param name="dto">學(xué)生參數(shù)</param>
          public async Task CreateAsync( StudentDto dto ) {
              var entity = dto.MapTo<Student>();
              ...
          }
        
      • 調(diào)用形式2: 源對(duì)象實(shí)例.MapTo(目標(biāo)類型實(shí)例)

        當(dāng)目標(biāo)類型實(shí)例已經(jīng)存在時(shí)使用該重載.

        • 范例:
          /// <summary>
          /// 創(chuàng)建學(xué)生
          /// </summary>
          /// <param name="dto">學(xué)生參數(shù)</param>
          public async Task CreateAsync( StudentDto dto ) {
              var entity = new Student();
              dto.MapTo(entity);
              ...
          }
        

      MapToList 擴(kuò)展方法

      Util應(yīng)用框架在 IEnumerable 擴(kuò)展了 MapToList 方法.

      如果要轉(zhuǎn)換集合,使用該擴(kuò)展.

      范例

      將 StudentDto 集合轉(zhuǎn)換為 Student 集合.

      傳入泛型參數(shù) Student ,而不是 List<Student> .

      List<StudentDto> dtos = new List<StudentDto> { new() { Name = "a" }, new() { Name = "b" } };
      List<Student> entities = dtos.MapToList<Student>();
      

      配置 AutoMapper

      對(duì)于簡單場景,比如轉(zhuǎn)換對(duì)象的屬性都相同, 不需要任何配置.

      AutoMapper服務(wù)注冊(cè)器自動(dòng)完成基礎(chǔ)配置.

      不過很多業(yè)務(wù)場景轉(zhuǎn)換的對(duì)象具有差異,需要配置差異部分.

      Util.ObjectMapping.IAutoMapperConfig

      Util提供了 AutoMapper 配置接口 IAutoMapperConfig.

      /// <summary>
      /// AutoMapper配置
      /// </summary>
      public interface IAutoMapperConfig {
          /// <summary>
          /// 配置映射
          /// </summary>
          /// <param name="expression">配置映射表達(dá)式</param>
          void Config( IMapperConfigurationExpression expression );
      }
      

      Config 配置方法提供配置映射表達(dá)式 IMapperConfigurationExpression 實(shí)例,它是 AutoMapper 配置入口.

      由 AutoMapper 服務(wù)注冊(cè)器掃描執(zhí)行所有 IAutoMapperConfig 配置.

      約定: 將 AutoMapper 配置類放置在 ObjectMapping 目錄中.

      為每一對(duì)有差異的對(duì)象實(shí)現(xiàn)該接口.

      修改學(xué)生示例,把 StudentDto 的 Name 屬性名改為 FullName.

      由于學(xué)生實(shí)體和DTO的Name屬性名不同,所以不能自動(dòng)轉(zhuǎn)換,需要配置.

      需要配置兩個(gè)映射方向.

      • 從 Student 到 StudentDto.

      • 從 StudentDto 到 Student.

      /// <summary>
      /// 學(xué)生
      /// </summary>
      public class Student : AggregateRoot<Student> {
          /// <summary>
          /// 初始化學(xué)生
          /// </summary>
          public Student() : this( Guid.Empty ) {
          }
      
          /// <summary>
          /// 初始化學(xué)生
          /// </summary>
          /// <param name="id">學(xué)生標(biāo)識(shí)</param>
          public Student( Guid id ) : base( id ) {
          }
      
          /// <summary>
          /// 姓名
          ///</summary>
          public string Name { get; set; }
      
          /// <summary>
          /// 出生日期
          ///</summary>
          public DateTime? Birthday { get; set; }
      }
      
      /// <summary>
      /// 學(xué)生參數(shù)
      /// </summary>
      public class StudentDto : DtoBase {
          /// <summary>
          /// 姓名
          ///</summary>
          public string FullName { get; set; }
          /// <summary>
          /// 出生日期
          ///</summary>
          public DateTime? Birthday { get; set; }
      }
      
      /// <summary>
      /// 學(xué)生映射配置
      /// </summary>
      public class StudentAutoMapperConfig : IAutoMapperConfig {
          /// <summary>
          /// 配置映射
          /// </summary>
          /// <param name="expression">配置映射表達(dá)式</param>
          public void Config( IMapperConfigurationExpression expression ) {
              expression.CreateMap<Student, StudentDto>()
                  .ForMember( t => t.FullName, t => t.MapFrom( r => r.Name ) );
              expression.CreateMap<StudentDto,Student>()
                  .ForMember( t => t.Name, t => t.MapFrom( r => r.FullName ) );
          }
      }
      

      對(duì)象間映射最佳實(shí)踐

      應(yīng)該盡量避免配置,保持代碼簡單.

      • 統(tǒng)一對(duì)象屬性

        如果有可能,盡量統(tǒng)一對(duì)象屬性名稱和屬性類型.

      • 使用 AutoMapper 映射約定

        AutoMapper 支持一些約定的映射方式.

        范例

        添加班級(jí)類型,學(xué)生實(shí)體添加班級(jí)關(guān)聯(lián)實(shí)體 Class, 學(xué)生DTO添加班級(jí)名稱屬性 ClassName.

          /// <summary>
          /// 學(xué)生
          /// </summary>
          public class Student : AggregateRoot<Student> {
              /// <summary>
              /// 初始化學(xué)生
              /// </summary>
              public Student() : this( Guid.Empty ) {
              }
        
              /// <summary>
              /// 初始化學(xué)生
              /// </summary>
              /// <param name="id">學(xué)生標(biāo)識(shí)</param>
              public Student( Guid id ) : base( id ) {
                  Class = new Class();
              }
        
              /// <summary>
              /// 姓名
              ///</summary>
              public string Name { get; set; }
        
              /// <summary>
              /// 出生日期
              ///</summary>
              public DateTime? Birthday { get; set; }
        
              /// <summary>
              /// 班級(jí)
              /// </summary>
              public Class Class { get; set; }
          }
        
          /// <summary>
          /// 班級(jí)
          /// </summary>
          public class Class : AggregateRoot<Class> {
              /// <summary>
              /// 初始化班級(jí)
              /// </summary>
              public Class() : this( Guid.Empty ) {
              }
        
              /// <summary>
              /// 初始化班級(jí)
              /// </summary>
              /// <param name="id">班級(jí)標(biāo)識(shí)</param>
              public Class( Guid id ) : base( id ) {
              }
        
              /// <summary>
              /// 班級(jí)名稱
              ///</summary>
              public string Name { get; set; }
          }
        
          /// <summary>
          /// 學(xué)生參數(shù)
          /// </summary>
          public class StudentDto : DtoBase {
              /// <summary>
              /// 姓名
              ///</summary>
              public string Name { get; set; }
              /// <summary>
              /// 班級(jí)名稱
              ///</summary>
              public string ClassName { get; set; }
              /// <summary>
              /// 出生日期
              ///</summary>
              public DateTime? Birthday { get; set; }
          }
        

        將 Student 的 Class實(shí)體 Name 屬性映射到 StudentDto 的 ClassName 屬性 ,不需要配置.

        var entity = new Student { Class = new Class { Name = "a" } };
        var dto = entity.MapTo<StudentDto>();
        //dto.ClassName 值為 a
        

        但不支持從 StudentDto 的 ClassName 屬性映射到 Student 的 Class實(shí)體 Name 屬性.

        var dto = new StudentDto { ClassName = "a" };
        var entity = dto.MapTo<Student>();
        //entity.Class.Name 值為 null
        

      源碼解析

      對(duì)象映射器 IObjectMapper

      你不需要調(diào)用 IObjectMapper 接口,始終通過 MapTo 擴(kuò)展方法進(jìn)行轉(zhuǎn)換.

      ObjectMapper 實(shí)現(xiàn)了 IObjectMapper 接口.

      ObjectMapper映射源類型和目標(biāo)類型時(shí),如果發(fā)現(xiàn)尚未配置映射關(guān)系,則自動(dòng)配置.

      除了自動(dòng)配置映射關(guān)系外,還需要處理并發(fā)和異常情況.

      /// <summary>
      /// 對(duì)象映射器
      /// </summary>
      public interface IObjectMapper {
          /// <summary>
          /// 將源對(duì)象映射到目標(biāo)對(duì)象
          /// </summary>
          /// <typeparam name="TSource">源類型</typeparam>
          /// <typeparam name="TDestination">目標(biāo)類型</typeparam>
          /// <param name="source">源對(duì)象</param>
          TDestination Map<TSource, TDestination>( TSource source );
          /// <summary>
          /// 將源對(duì)象映射到目標(biāo)對(duì)象
          /// </summary>
          /// <typeparam name="TSource">源類型</typeparam>
          /// <typeparam name="TDestination">目標(biāo)類型</typeparam>
          /// <param name="source">源對(duì)象</param>
          /// <param name="destination">目標(biāo)對(duì)象</param>
          TDestination Map<TSource, TDestination>( TSource source, TDestination destination );
      }
      
      /// <summary>
      /// AutoMapper對(duì)象映射器
      /// </summary>
      public class ObjectMapper : IObjectMapper {
          /// <summary>
          /// 最大遞歸獲取結(jié)果次數(shù)
          /// </summary>
          private const int MaxGetResultCount = 16;
          /// <summary>
          /// 同步鎖
          /// </summary>
          private static readonly object Sync = new();
          /// <summary>
          /// 配置表達(dá)式
          /// </summary>
          private readonly MapperConfigurationExpression _configExpression;
          /// <summary>
          /// 配置提供器
          /// </summary>
          private IConfigurationProvider _config;
          /// <summary>
          /// 對(duì)象映射器
          /// </summary>
          private IMapper _mapper;
      
          /// <summary>
          /// 初始化AutoMapper對(duì)象映射器
          /// </summary>
          /// <param name="expression">配置表達(dá)式</param>
          public ObjectMapper( MapperConfigurationExpression expression ) {
              _configExpression = expression ?? throw new ArgumentNullException( nameof( expression ) );
              _config = new MapperConfiguration( expression ); 
              _mapper = _config.CreateMapper();
          }
      
          /// <summary>
          /// 將源對(duì)象映射到目標(biāo)對(duì)象
          /// </summary>
          /// <typeparam name="TSource">源類型</typeparam>
          /// <typeparam name="TDestination">目標(biāo)類型</typeparam>
          /// <param name="source">源對(duì)象</param>
          public TDestination Map<TSource, TDestination>( TSource source ) {
              return Map<TSource, TDestination>( source, default );
          }
      
          /// <summary>
          /// 將源對(duì)象映射到目標(biāo)對(duì)象
          /// </summary>
          /// <typeparam name="TSource">源類型</typeparam>
          /// <typeparam name="TDestination">目標(biāo)類型</typeparam>
          /// <param name="source">源對(duì)象</param>
          /// <param name="destination">目標(biāo)對(duì)象</param>
          public TDestination Map<TSource, TDestination>( TSource source, TDestination destination ) {
              if ( source == null )
                  return default;
              var sourceType = GetType( source );
              var destinationType = GetType( destination );
              return GetResult( sourceType, destinationType, source, destination,0 );
          }
      
          /// <summary>
          /// 獲取類型
          /// </summary>
          private Type GetType<T>( T obj ) {
              if( obj == null )
                  return GetType( typeof( T ) );
              return GetType( obj.GetType() );
          }
      
          /// <summary>
          /// 獲取類型
          /// </summary>
          private Type GetType( Type type ) {
              return Reflection.GetElementType( type );
          }
      
          /// <summary>
          /// 獲取結(jié)果
          /// </summary>
          private TDestination GetResult<TDestination>( Type sourceType, Type destinationType, object source, TDestination destination,int i ) {
              try {
                  if ( i >= MaxGetResultCount )
                      return default;
                  i += 1;
                  if ( Exists( sourceType, destinationType ) )
                      return GetResult( source, destination );
                  lock ( Sync ) {
                      if ( Exists( sourceType, destinationType ) )
                          return GetResult( source, destination );
                      ConfigMap( sourceType, destinationType );
                  }
                  return GetResult( source, destination );
              }
              catch ( AutoMapperMappingException ex ) {
                  if ( ex.InnerException != null && ex.InnerException.Message.StartsWith( "Missing type map configuration" ) )
                      return GetResult( GetType( ex.MemberMap.SourceType ), GetType( ex.MemberMap.DestinationType ), source, destination,i );
                  throw;
              }
          }
      
          /// <summary>
          /// 是否已存在映射配置
          /// </summary>
          private bool Exists( Type sourceType, Type destinationType ) {
              return _config.Internal().FindTypeMapFor( sourceType, destinationType ) != null;
          }
      
          /// <summary>
          /// 獲取映射結(jié)果
          /// </summary>
          private TDestination GetResult<TSource, TDestination>( TSource source, TDestination destination ) {
              return _mapper.Map( source, destination );
          }
      
          /// <summary>
          /// 動(dòng)態(tài)配置映射
          /// </summary>
          private void ConfigMap( Type sourceType, Type destinationType ) {
              _configExpression.CreateMap( sourceType, destinationType );
              _config = new MapperConfiguration( _configExpression );
              _mapper = _config.CreateMapper();
          }
      }
      

      AutoMapper服務(wù)注冊(cè)器

      AutoMapper服務(wù)注冊(cè)器掃描 IAutoMapperConfig 配置并執(zhí)行.

      同時(shí)為 MapTo 擴(kuò)展類 ObjectMapperExtensions 設(shè)置 IObjectMapper 實(shí)例.

      /// <summary>
      /// AutoMapper服務(wù)注冊(cè)器
      /// </summary>
      public class AutoMapperServiceRegistrar : IServiceRegistrar {
          /// <summary>
          /// 獲取服務(wù)名
          /// </summary>
          public static string ServiceName => "Util.ObjectMapping.Infrastructure.AutoMapperServiceRegistrar";
      
          /// <summary>
          /// 排序號(hào)
          /// </summary>
          public int OrderId => 300;
      
          /// <summary>
          /// 是否啟用
          /// </summary>
          public bool Enabled => ServiceRegistrarConfig.IsEnabled( ServiceName );
      
          /// <summary>
          /// 注冊(cè)服務(wù)
          /// </summary>
          /// <param name="serviceContext">服務(wù)上下文</param>
          public Action Register( ServiceContext serviceContext ) {
              var types = serviceContext.TypeFinder.Find<IAutoMapperConfig>();
              var instances = types.Select( type => Reflection.CreateInstance<IAutoMapperConfig>( type ) ).ToList();
              var expression = new MapperConfigurationExpression();
              instances.ForEach( t => t.Config( expression ) );
              var mapper = new ObjectMapper( expression );
              ObjectMapperExtensions.SetMapper( mapper );
              serviceContext.HostBuilder.ConfigureServices( ( context, services ) => {
                  services.AddSingleton<IObjectMapper>( mapper );
              } );
              return null;
          }
      }
      

      對(duì)象映射擴(kuò)展 ObjectMapperExtensions

      ObjectMapperExtensions 提供了 MapToMapToList 擴(kuò)展方法.

      MapTo 擴(kuò)展方法依賴 IObjectMapper 實(shí)例,由于擴(kuò)展方法是靜態(tài)方法,所以需要將 IObjectMapper 定義為靜態(tài)變量.

      通過 SetMapper 靜態(tài)方法將對(duì)象映射器實(shí)例傳入.

      對(duì)象映射器 ObjectMapper 實(shí)例作為靜態(tài)變量,必須處理并發(fā)相關(guān)的問題.

      /// <summary>
      /// 對(duì)象映射擴(kuò)展
      /// </summary>
      public static class ObjectMapperExtensions {
          /// <summary>
          /// 對(duì)象映射器
          /// </summary>
          private static IObjectMapper _mapper;
      
          /// <summary>
          /// 設(shè)置對(duì)象映射器
          /// </summary>
          /// <param name="mapper">對(duì)象映射器</param>
          public static void SetMapper( IObjectMapper mapper ) {
              _mapper = mapper ?? throw new ArgumentNullException( nameof( mapper ) );
          }
      
          /// <summary>
          /// 將源對(duì)象映射到目標(biāo)對(duì)象
          /// </summary>
          /// <typeparam name="TDestination">目標(biāo)類型</typeparam>
          /// <param name="source">源對(duì)象</param>
          public static TDestination MapTo<TDestination>( this object source ) {
              if ( _mapper == null )
                  throw new ArgumentNullException( nameof(_mapper) );
              return _mapper.Map<object, TDestination>( source );
          }
              
          /// <summary>
          /// 將源對(duì)象映射到目標(biāo)對(duì)象
          /// </summary>
          /// <typeparam name="TSource">源類型</typeparam>
          /// <typeparam name="TDestination">目標(biāo)類型</typeparam>
          /// <param name="source">源對(duì)象</param>
          /// <param name="destination">目標(biāo)對(duì)象</param>
          public static TDestination MapTo<TSource, TDestination>( this TSource source, TDestination destination ) {
              if( _mapper == null )
                  throw new ArgumentNullException( nameof( _mapper ) );
              return _mapper.Map( source, destination );
          }
      
          /// <summary>
          /// 將源集合映射到目標(biāo)集合
          /// </summary>
          /// <typeparam name="TDestination">目標(biāo)元素類型,范例:Sample,不要加List</typeparam>
          /// <param name="source">源集合</param>
          public static List<TDestination> MapToList<TDestination>( this System.Collections.IEnumerable source ) {
              return MapTo<List<TDestination>>( source );
          }
      }
      

      禁用 AutoMapper 服務(wù)注冊(cè)器

      ServiceRegistrarConfig.Instance.DisableAutoMapperServiceRegistrar();
      
      posted @ 2023-11-03 13:33  何鎮(zhèn)汐  閱讀(596)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 成人看的污污超级黄网站免费| 国产综合视频一区二区三区| 欧美成人片一区二区三区| 欧洲亚洲成av人片天堂网| 小雪被老外黑人撑破了视频| 97久久精品人人做人人爽| 国产午夜福利视频一区二区| 妺妺窝人体色www看美女| 国产成人一区二区三区免费| 日日猛噜噜狠狠扒开双腿小说 | 国产日韩av二区三区| 国产精品中文字幕一区| 久久毛片少妇高潮| 成人网站免费在线观看| 久热这里只有精品视频3| 久久久久中文伊人久久久| 人人爽人人模人人人爽人人爱| 另类专区一区二区三区| 亚洲小说乱欧美另类| 免费观看性行为视频的网站| 老色批国产在线观看精品 | 日日碰狠狠添天天爽| 国产在线精品欧美日韩电影 | 亚洲日韩成人av无码网站| 日本极品少妇videossexhd| 欧美人禽zozo动人物杂交| 无码av片在线观看免费| 亚洲中文字幕日产无码成人片| 日本无码欧美一区精品久久| 2020中文字字幕在线不卡| 亚洲日韩性欧美中文字幕| 日本阿v片在线播放免费| 国产精品中文av专线| 国产精品亚洲一区二区在| 2018av天堂在线视频精品观看 | 亚洲精品动漫免费二区| 欧美白妞大战非洲大炮| 国产一区二区精品久久呦| 鹤壁市| 亚洲欧美色综合影院| 亚洲男人第一无码av网|