亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > .NET > 正文

解析ABP框架領域層中的實體類與倉儲類

2024-07-10 13:30:43
字體:
來源:轉載
供稿:網友

領域層
實體是DDD(領域驅動設計)的核心概念之一。Eric Evans是這樣描述的“很多對象不是通過它們的屬性定義的,而是通過一連串的連續性事件和標識定義的”(引用領域驅動設計一書)。

譯者注:對象不是通過它們的屬性來下根本性的定義,而應該是通過它的線性連續性和標識性定義的。。所以,實體是具有唯一標識的ID且存儲在數據庫中。實體通常被映射成數據庫中的一個表。

實體類(Entity classes)
在ABP中,實體繼承自Entity類,請看下面示例:

public class Person : Entity{  public virtual string Name { get; set; }  public virtual DateTime CreationTime { get; set; }  public Task()  {    CreationTime = DateTime.Now;  }}

Person 類被定義為一個實體。它具有兩個屬性,它的父類中有Id屬性。Id是該實體的主鍵。所以,Id是所有繼承自Entity類的實體的主鍵(所有實體的主鍵都是Id字段)。

Id(主鍵)數據類型可以被更改。默認是int(int32)類型。如果你想給Id定義其它類型,你應該像下面示例一樣來聲明Id的類型。

public class Person : Entity<long>{  public virtual string Name { get; set; }  public virtual DateTime CreationTime { get; set; }  public Task()  {    CreationTime = DateTime.Now;  }}

你可以設置為string,Guid或者其它數據類型。

實體類重寫了 equality (==) 操作符用來判斷兩個實體對象是否相等(兩個實體的Id是否相等)。還定義了一個IsTransient()方法來檢測實體是否有Id屬性。

接口約定
在很多應用程序中,很多實體具有像CreationTime的屬性(數據庫表也有該字段)用來指示該實體是什么時候被創建的。APB提供了一些有用的接口來實現這些類似的功能。也就是說,為這些實現了這些接口的實體,提供了一個通用的編碼方式(通俗的說只要實現指定的接口就能實現指定的功能)。

(1)審計(Auditing)

實體類實現 IHasCreationTime 接口就可以具有CreationTime的屬性。當該實體被插入到數據庫時, ABP會自動設置該屬性的值為當前時間。

public interface IHasCreationTime{  DateTime CreationTime { get; set; }}

Person類可以被重寫像下面示例一樣實現IHasCreationTime 接口:

public class Person : Entity<long>, IHasCreationTime{  public virtual string Name { get; set; }  public virtual DateTime CreationTime { get; set; }  public Task()  {    CreationTime = DateTime.Now;  }}

ICreationAudited 擴展自 IHasCreationTime 并且該接口具有屬性 CreatorUserId :

public interface ICreationAudited : IHasCreationTime{  long? CreatorUserId { get; set; }}

當保存一個新的實體時,ABP會自動設置CreatorUserId 的屬性值為當前用戶的Id

你可以輕松的實現ICreationAudited接口,通過派生自實體類 CreationAuditedEntity (因為該類已經實現了ICreationAudited接口,我們可以直接繼承CreationAuditedEntity 類就實現了上述功能)。它有一個實現不同ID數據類型的泛型版本(默認是int),可以為ID(Entity類中的ID)賦予不同的數據類型。
下面是一個為實現類似修改功能的接口

public interface IModificationAudited{  DateTime? LastModificationTime { get; set; }  long? LastModifierUserId { get; set; }}

當更新一個實體時,ABP會自動設置這些屬性的值。你只需要在你的實體類里面實現這些屬性。

如果你想實現所有的審計屬性,你可以直接擴展 IAudited 接口;示例如下:

public interface IAudited : ICreationAudited, IModificationAudited{    }

作為一個快速開發方式,你可以直接派生自AuditedEntity 類,不需要再去實現IAudited接口(AuditedEntity 類已經實現了該功能,直接繼承該類就可以實現上述功能),AuditedEntity 類有一個實現不同ID數據類型的泛型版本(默認是int),可以為ID(Entity類中的ID)賦予不同的數據類型。

(2)軟刪除(Soft delete)

軟刪除是一個通用的模式被用來標記一個已經被刪除的實體,而不是實際從數據庫中刪除記錄。例如:你可能不想從數據庫中硬刪除一條用戶記錄,因為它被許多其它的表所關聯。為了實現軟刪除的目的我們可以實現該接口 ISoftDelete:

public interface ISoftDelete{  bool IsDeleted { get; set; }}

ABP實現了開箱即用的軟刪除模式。當一個實現了軟刪除的實體正在被被刪除,ABP會察覺到這個動作,并且阻止其刪除,設置IsDeleted 屬性值為true并且更新數據庫中的實體。也就是說,被軟刪除的記錄不可以從數據庫中檢索出,ABP會為我們自動過濾軟刪除的記錄。(例如:Select查詢,這里指通過ABP查詢,不是通過數據庫中的查詢分析器查詢。)

如果你用了軟刪除,你有可能也想實現這個功能,就是記錄誰刪除了這個實體。要實現該功能你可以實現IDeletionAudited 接口,請看下面示例:

public interface IDeletionAudited : ISoftDelete{  long? DeleterUserId { get; set; }  DateTime? DeletionTime { get; set; }}

正如你所看到的IDeletionAudited 擴展自 ISoftDelete接口。當一個實體被刪除的時候ABP會自動的為這些屬性設置值。
如果你想為實體類擴展所有的審計接口(例如:創建(creation),修改(modification)和刪除(deletion)),你可以直接實現IFullAudited接口,因為該接口已經繼承了這些接口,請看下面示例:

public interface IFullAudited : IAudited, IDeletionAudited{    }

作為一個快捷方式,你可以直接從FullAuditedEntity 類派生你的實體類,因為該類已經實現了IFullAudited接口。

注意:所有的審計接口和類都有一個泛型模板為了導航定義屬性到你的User 實體(例如:ICreationAudited<TUser>和FullAuditedEntity<TPrimaryKey, TUser>),這里的TUser指的進行創建,修改和刪除的用戶的實體類的類型,詳細請看源代碼(Abp.Domain.Entities.Auditing空間下的FullAuditedEntity<TPrimaryKey, TUser>類),TprimaryKey 只的是Entity基類Id類型,默認是int。

(3)激活狀態/閑置狀態(Active/Passive)

有些實體需要被標記為激活狀態或者閑置狀態。那么你可以為實體采取active/passive狀態的行動?;谶@個原因而創建的實體,你可以擴展IPassivable 接口來實現該功能。該接口定義了IsActive 的屬性。

如果你首次創建的實體被標記為激活狀態,你可以在構造函數設置IsActive屬性值為true。

這是不同于軟刪除(IsDeleted)。如果實體被軟刪除,它不能從數據庫中被檢索到(ABP已經過濾了軟刪除記錄)。但是對于激活狀態/閑置狀態的實體,你完全取決于你怎樣去獲取這些被標記了的實體。

IEntity接口
事實上Entity 實現了IEntity 接口(和Entity<TPrimaryKey> 實現了 IEntity<TPrimaryKey>接口)。如果你不想從Entity 類派生,你能直接的實現這些接口。其他實體類也可以實現相應的接口。但是不建議你用這種方式。除非你有一個很好的理由不從Entity 類派生。


倉儲(Repositories)
倉儲定義:“在領域層和數據映射層的中介,使用類似集合的接口來存取領域對象”(Martin Fowler)。

實際上,倉儲被用于領域對象在數據庫上的操作(實體Entity和值對象Value types)。一般來說,我們針對不同的實體(或聚合根Aggregate Root)會創建相對應的倉儲。

IRepository接口
在ABP中,倉儲類要實現IRepository接口。最好的方式是針對不同倉儲對象定義各自不同的接口。

針對Person實體的倉儲接口聲明的示例如下所示:

public interface IPersonRepository : IRepository<Person> {}

IPersonRepository繼承自IRepository<TEntity>,用來定義Id的類型為int(Int32)的實體。如果你的實體Id數據類型不是int,你可以繼承IRepository<TEntity, TPrimaryKey>接口,如下所示:

public interface IPersonRepository : IRepository<Person, long> { }

對于倉儲類,IRepository定義了許多泛型的方法。比如: Select,Insert,Update,Delete方法(CRUD操作)。在大多數的時候,這些方法已足已應付一般實體的需要。如果這些方對于實體來說已足夠,我們便不需要再去創建這個實體所需的倉儲接口/類。在Implementation章節有更多細節。

(1)查詢(Query)

IRepository定義了從數據庫中檢索實體的常用方法。

A、取得單一實體(Getting single entity):

TEntity Get(TPrimaryKey id);Task<TEntity> GetAsync(TPrimaryKey id);TEntity Single(Expression<Func<TEntity, bool>> predicate);TEntity FirstOrDefault(TPrimaryKey id);Task<TEntity> FirstOrDefaultAsync(TPrimaryKey id);TEntity FirstOrDefault(Expression<Func<TEntity, bool>> predicate);Task<TEntity> FirstOrDefaultAsync(Expression<Func<TEntity, bool>> predicate);TEntity Load(TPrimaryKey id);

Get方法被用于根據主鍵值(Id)取得對應的實體。當數據庫中根據主鍵值找不到相符合的實體時,它會拋出例外。Single方法類似Get方法,但是它的輸入參數是一個表達式而不是主鍵值(Id)。因此,我們可以寫Lambda表達式來取得實體。示例如下:

var person = _personRepository.Get(42);var person = _personRepository.Single(p => o.Name == "Halil ibrahim Kalkan");

注意,Single方法會在給出的條件找不到實體或符合的實體超過一個以上時,都會拋出例外。

FirstOrDefault也一樣,但是當沒有符合Lambda表達式或Id的實體時,會回傳null(取代拋出異常)。當有超過一個以上的實體符合條件,它只會返回第一個實體。

Load并不會從數據庫中檢索實體,但它會創建延遲執行所需的代理對象。如果你只使用Id屬性,實際上并不會檢索實體,它只有在你存取想要查詢實體的某個屬性時才會從數據庫中查詢實體。當有性能需求的時候,這個方法可以用來替代Get方法。Load方法在NHibernate與ABP的整合中也有實現。如果ORM提供者(Provider)沒有實現這個方法,Load方法運行的會和Get方法一樣。

ABP有些方法具有異步(Async)版本,可以應用在異步開發模型上(見Async方法相關章節)。

B、取得實體列表(Getting list of entities):

List<TEntity> GetAllList();Task<List<TEntity>> GetAllListAsync();List<TEntity> GetAllList(Expression<Func<TEntity, bool>> predicate);Task<List<TEntity>> GetAllListAsync(Expression<Func<TEntity, bool>> predicate);IQueryable<TEntity> GetAll();

GetAllList被用于從數據庫中檢索所有實體。重載并且提供過濾實體的功能,如下:

var allPeople = _personRespository.GetAllList();var somePeople = _personRepository.GetAllList(person => person.IsActive && person.Age > 42);
GetAll返回IQueryable<T>類型的對象。因此我們可以在調用完這個方法之后進行Linq操作。示例:
//例子一var query = from person in _personRepository.GetAll()where person.IsActiveorderby person.Nameselect person;var people = query.ToList();//例子二List<Person> personList2 = _personRepository.GetAll().Where(p => p.Name.Contains("H")).OrderBy(p => p.Name).Skip(40).Take(20).ToList();

 如果調用GetAll方法,那么幾乎所有查詢都可以使用Linq完成。甚至可以用它來編寫Join表達式。

說明:關于IQueryable<T>
當你調用GetAll這個方法在Repository對象以外的地方,必定會開啟數據庫連接。這是因為IQueryable<T>允許延遲執行。它會直到你調用ToList方法或在forEach循環上(或是一些存取已查詢的對象方法)使用IQueryable<T>時,才會實際執行數據庫的查詢。因此,當你調用ToList方法時,數據庫連接必需是啟用狀態。我們可以使用ABP所提供的UnitOfWork特性在調用的方法上來實現。注意,Application Service方法預設都已經是UnitOfWork。因此,使用了GetAll方法就不需要如同Application Service的方法上添加UnitOfWork特性。

有些方法擁有異步版本,可應用在異步開發模型(見關于async方法章節)。

自定義返回值(Custom return value)

ABP也有一個額外的方法來實現IQueryable<T>的延遲加載效果,而不需要在調用的方法上添加UnitOfWork這個屬性卷標。

T Query<T>(Func<IQueryable<Tentity>,T> queryMethod);
查詢方法接受Lambda(或一個方法)來接收IQueryable<T>并且返回任何對象類型。示例如下:

var  people = _personRepository.Query(q => q.Where(p => p.Name.Contains("H")).OrderBy(p => p.Name).ToList());
因為是采用Lambda(或方法)在倉儲對象的方法中執行,它會在數據庫連接開啟之后才被執行。你可以返回實體集合,或一個實體,或一個具部份字段(注: 非Select *)或其它執行查詢后的查詢結果集。

(2)新增(insert)

IRepository接口定義了簡單的方法來提供新增一個實體到數據庫:

TEntity Insert(TEntity entity);Task<TEntity> InsertAsync(TEntity entity);TPrimaryKey InsertAndGetId(TEntity entity);Task<TPrimaryKey> InsertAndGetIdAsync(TEntity entity);TEntity InsertOrUpdate(TEntity entity);Task<TEntity> InsertOrUpdateAsync(TEntity entity);TPrimaryKey InsertOrUpdateAndGetId(TEntity entity);Task<TPrimaryKey> InsertOrUpdateAndGetIdAsync(TEntity entity);
新增方法會新增實體到數據庫并且返回相同的已新增實體。InsertAndGetId方法返回新增實體的標識符(Id)。當我們采用自動遞增標識符值且需要取得實體的新產生標識符值時非常好用。InsertOfUpdate會新增或更新實體,選擇那一種是根據Id是否有值來決定。最后,InsertOrUpdatedAndGetId會在實體被新增或更新后返回Id值。

所有的方法都擁有異步版本可應用在異步開發模型(見關于異步方法章節)

(3)更新(UPDATE)

IRepository定義一個方法來實現更新一個已存在于數據庫中的實體。它更新實體并返回相同的實體對象。

TEntity Update(TEntity entity);Task<TEntity> UpdateAsync(TEntity entity);
(4)刪除(Delete)

IRepository定了一些方法來刪除已存在數據庫中實體。

void Delete(TEntity entity);Task DeleteAsync(TEntity entity);void Delete(TPrimaryKey id);Task DeleteAsync(TPrimaryKey id);void Delete(Expression<Func<TEntity, bool>> predicate);Task DeleteAsync(Expression<Func<TEntity, bool>> predicate);
第一個方法接受一個現存的實體,第二個方法接受現存實體的Id。

最后一個方法接受一個條件來刪除符合條件的實體。要注意,所有符合predicate表達式的實體會先被檢索而后刪除。因此,使用上要很小心,這是有可能造成許多問題,假如果有太多實體符合條件。

所有的方法都擁有async版本來應用在異步開發模型(見關于異步方法章節)。

(5)其它方法(others)

IRepository也提供一些方法來取得數據表中實體的數量。

int Count();Task<int> CountAsync();int Count(Expression<Func<TEntity, bool>> predicate);Task<int> CountAsync(Expression<Func<TEntity, bool>> predicate);Long LongCount();Task<long> LongCountAsync();Long LongCount(Expression<Func<TEntity, bool>> predicate);Task<long> LongCountAsync(Expression<TEntity, bool>> predicate);

 所有的方法都擁有async版本被應用在異步開發模型(見關于異步方法章節)。

(6)關于異步方法(About Async methods)

ABP支持異步開發模型。因此,倉儲方法擁有Async版本。在這里有一個使用異步模型的application service方法的示例:

public class PersonAppService : AbpWpfDemoAppServiceBase, IPersonAppService{  private readonly IRepository<Person> _personRepository;  public PersonAppService(IRepository<Person> personRepository)  {    _personRepository = personRepository;  }  public async Task<GetPeopleOutput> GetAllPeople()  {    var people = await _personRepository.GetAllListAsync();          return new GetPeopleOutput    {      People = Mapper.Map<List<PersonDto>>(people)    };  }}

GetAllPeople方法是異步的并且使用GetAllListAsync與await保留關鍵字。

Async不是在每個ORM框架都有提供。

上例是從EF所提供的異步能力。如果ORM框架沒有提供Async的倉儲方法則它會以同步的方式操作。同樣地,舉例來說,InsertAsync操作起來和EF的新增是一樣的,因為EF會直到單元作業(unit of work)完成之后才會寫入新實體到數據庫中(DbContext.SaveChanges)。

倉儲的實現
ABP在設計上是采取不指定特定ORM框架或其它存取數據庫技術的方式。只要實現IRepository接口,任何框架都可以使用。

倉儲要使用NHibernate或EF來實現都很簡單。

EntityFramework
當你使用NHibernate或EntityFramework,如果提供的方法已足夠使用,你就不需要為你的實體創建倉儲對象了。我們可以直接注入IRepository<TEntity>(或IRepository<TEntity, TPrimaryKey>)。下面的示例為application service使用倉儲對象來新增實體到數據庫:

public class PersonAppService : IPersonAppService{  private readonly IRepository<Person> _personRepository;  public PersonAppService(IRepository<Person> personRepository)  {    _personRepository = personRepository;  }  public void CreatePerson(CreatePersonInput input)  {        person = new Person { Name = input.Name, EmailAddress = input.EmailAddress };        _personRepository.Insert(person);  }}

 PersonAppService的建構子注入了IRepository<Person>并且使用其Insert方法。當你有需要為實體創建一個客制的倉儲方法,那么你就應該創建一個倉儲類給指定的實體。

管理數據庫連接
數據庫連接的開啟和關閉,在倉儲方法中,ABP會自動化的進行連接管理。

當倉儲方法被調用后,數據庫連接會自動開啟且啟動事務。當倉儲方法執行結束并且返回以后,所有的實體變化都會被儲存, 事務被提交并且數據庫連接被關閉,一切都由ABP自動化的控制。如果倉儲方法拋出任何類型的異常,事務會自動地回滾并且數據連接會被關閉。上述所有操作在實現了IRepository接口的倉儲類所有公開的方法中都可以被調用。

如果倉儲方法調用其它倉儲方法(即便是不同倉儲的方法),它們共享同一個連接和事務。連接會由倉儲方法調用鏈最上層的那個倉儲方法所管理。更多關于數據庫管理,詳見UnitOfWork文件。

儲的生命周期
所有的倉儲對象都是暫時性的。這就是說,它們是在有需要的時候才會被創建。ABP大量的使用依賴注入,當倉儲類需要被注入的時候,新的類實體會由注入容器會自動地創建。見相根據注入文件有更多信息。

倉儲的最佳實踐
對于一個T類型的實體,是可以使用IRepository<T>。但別任何情況下都創建定制化的倉儲,除非我們真的很需要。預定義倉儲方法已經足夠應付各種案例。
假如你正創建定制的倉儲(可以實現IRepository<TEntity>)
倉儲類應該是無狀態的。這意味著, 你不該定義倉儲等級的狀態對象并且倉儲方法的調用也不應該影響到其它調用?!   ?br /> 當倉儲可以使用相根據注入,盡可較少或是不相根據于其它服務。 


注:相關教程知識閱讀請移步到ASP.NET教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
高清欧美性猛交xxxx黑人猛交| 精品国产一区二区三区久久狼黑人| 国产精品精品视频| 国产玖玖精品视频| 日韩中文字幕国产| 日韩高清av在线| 国产精品亚洲精品| 一区二区三区视频免费在线观看| 日韩中文在线中文网在线观看| 欧美精品久久久久久久久| 欧美一级片免费在线| 久久久免费精品| 国产精品网址在线| 国产mv免费观看入口亚洲| 在线精品视频视频中文字幕| 欧美日韩国产综合视频在线观看中文| 中文国产亚洲喷潮| 亚洲国产精品99| 日韩电影大片中文字幕| 国产精品爽爽爽爽爽爽在线观看| 亚洲人成网站色ww在线| 欧美激情综合色| 91欧美精品成人综合在线观看| 97热在线精品视频在线观看| 欧美日韩国产中文字幕| 成人国内精品久久久久一区| 亚洲人精品午夜在线观看| 在线视频日韩精品| 中文字幕最新精品| 超碰精品一区二区三区乱码| 5566成人精品视频免费| 欧美激情精品久久久久久黑人| 欧美性猛交xxxx免费看漫画| 97avcom| 日韩成人在线视频网站| 亚洲91精品在线观看| 亚洲欧美日韩天堂| …久久精品99久久香蕉国产| 亚洲精品日韩激情在线电影| 国产精品av在线| 伊人伊成久久人综合网站| 91手机视频在线观看| 精品久久久久久久久久久久| 久久久久久成人| 18久久久久久| 国产欧美日韩中文字幕在线| 亚洲福利视频二区| 国产精品免费久久久| 久久久99免费视频| 国产激情综合五月久久| 亚洲精品中文字| 91在线视频九色| 亚洲激情中文字幕| 中文国产成人精品久久一| 久久久综合免费视频| 欧美在线不卡区| 日韩视频亚洲视频| 亚洲精品电影在线观看| 国产精品久久久精品| 亚洲黄色av女优在线观看| 久久久久久国产免费| 成人高h视频在线| 91精品国产91久久久久久最新| 欧美激情图片区| 亚洲一区二区精品| 插插插亚洲综合网| 国产日本欧美视频| 日韩欧美有码在线| 在线观看亚洲视频| 国产精品揄拍一区二区| 国产亚洲美女久久| 久久综合88中文色鬼| 97婷婷涩涩精品一区| 国产美女精品免费电影| 最近更新的2019中文字幕| 日韩视频在线免费| 欧美在线亚洲一区| 亚洲精品久久久久国产| 情事1991在线| 国产精品久久久久免费a∨大胸| 国产欧美日韩中文字幕在线| 深夜福利日韩在线看| 97婷婷大伊香蕉精品视频| 精品毛片三在线观看| 亚洲欧洲视频在线| 久久久久成人精品| 久久在线视频在线| 国产精品午夜国产小视频| 亚洲字幕一区二区| 57pao国产精品一区| 精品国产91久久久久久老师| 欧美乱大交xxxxx另类电影| 91美女片黄在线观| 亚洲美女福利视频网站| 青青草99啪国产免费| 国产精品久久久亚洲| 国产剧情日韩欧美| 欧美视频一二三| 亚洲精品乱码久久久久久按摩观| 51视频国产精品一区二区| 欧美黑人性猛交| 国产美女扒开尿口久久久| 日韩成人中文字幕在线观看| xxx欧美精品| 欧美性猛交xxxx免费看漫画| 在线视频日本亚洲性| 欧美性资源免费| 欧洲亚洲妇女av| 欧美日韩免费在线观看| 日韩视频免费大全中文字幕| 不卡av在线播放| 国产免费成人av| 欧美巨猛xxxx猛交黑人97人| 亚洲精品女av网站| 国产精品成人国产乱一区| 色多多国产成人永久免费网站| 亚洲国产中文字幕在线观看| 在线国产精品视频| 8090理伦午夜在线电影| 国产日韩精品在线| 日韩精品极品在线观看播放免费视频| 91牛牛免费视频| 91久久久久久久一区二区| 欧美激情videos| 亚洲国产欧美一区二区三区久久| 国产日韩欧美在线视频观看| 日韩最新av在线| 成人国产亚洲精品a区天堂华泰| 岛国视频午夜一区免费在线观看| 精品国产电影一区| 91精品中文在线| 岛国精品视频在线播放| 国产精品久久久久77777| 国产精品久久综合av爱欲tv| 欧美在线视频在线播放完整版免费观看| 国产精品福利无圣光在线一区| 日韩电视剧免费观看网站| 国产精品99导航| 亚洲国产小视频| 日韩在线免费高清视频| 欧美xxxx14xxxxx性爽| 国产日本欧美视频| 日韩大陆毛片av| 亚洲美女在线观看| 91夜夜未满十八勿入爽爽影院| 精品电影在线观看| 亚洲乱码国产乱码精品精| 丰满岳妇乱一区二区三区| 亚洲无av在线中文字幕| 国产欧美韩国高清| 久久91亚洲人成电影网站| 久久精品亚洲热| 91香蕉嫩草神马影院在线观看| 久久在精品线影院精品国产| wwwwwwww亚洲| 日韩在线观看网站| 国产视频久久久久| 亚洲第一综合天堂另类专| 成人午夜两性视频| 亚洲人成电影网站| 精品人伦一区二区三区蜜桃网站| 亚洲精品98久久久久久中文字幕| 国产精品91久久久久久| 亚洲电影免费在线观看|