FlexFetcher เป็นไลบรารี .NET สำหรับการกรองการเรียงลำดับข้อมูลเพจ มันได้รับการออกแบบตามหลักการ OOP และสามารถใช้ในโครงการ. NET ใด ๆ : เว็บ, เดสก์ท็อป, มือถือ ฯลฯ FlexFetcher ได้รับแรงบันดาลใจจากรูปแบบวัตถุ Telerik Kendo UI Grid
มีห้องสมุดที่ยอดเยี่ยมมากมายสำหรับการกรองการเรียงลำดับข้อมูลเพจใน. NET: ตะแกรง, QueryKit, LightQuery ฯลฯ แต่ส่วนใหญ่ไม่ได้ออกแบบตามหลักการ OOP พวกเขามีไวยากรณ์การสืบค้นซึ่งมีจุดประสงค์เพื่ออ่านได้ง่ายเช่น (ตัวอย่างทั้งหมดนำมาจากเอกสารประกอบห้องสมุดเหล่านั้น):
sorts=LikeCount,CommentCount,-created&filters=LikeCount>10,Title@=awesome title,&page=1&pageSize=10
หรือ
""(Age ^^ [20, 30, 40]) && (BirthMonth ^^* ["January", "February", "March"]) || (Id ^^ ["6d623e92-d2cf-4496-a2df-f49fa77328ee"])""
หรือ
`?sort=country&thenSort=email desc`
แต่ในเวลาเดียวกัน:
FlexFetcher ไม่ดีกว่าหรือแย่กว่าห้องสมุดเหล่านั้นมันแตกต่างกัน ยอมรับการสืบค้นในรูปแบบของวัตถุซึ่งสามารถเป็นอนุกรม/deserialized ไปยัง/จาก JSON เช่นนี้:
?Filters={"Logic":"And","Filters":[{"Operator":"Eq","Field":"Address.Town","Value":"New York"}]}
หรือถ้าคุณต้องการรูปแบบขนาดกะทัดรัดมากกว่านี้:
?Filter={"L":"And","Fs":[{"O":"Eq","F":"Address.Town","V":"New York"}]}
หรือถ้าคุณต้องการใช้คำขอโพสต์ (สไตล์ RPC) เช่นนี้:
{
"Filters" : {
"Logic" : " and " ,
"Filters" : [
{
"Operator" : " eq " ,
"Field" : " Address.Town " ,
"Value" : " New York "
}
]
}
}รูปแบบนี้ง่ายต่อการอ่านและเข้าใจสำหรับมนุษย์ง่ายต่อการขยายง่ายต่อการอนุกรม/deserialize และใช้งานง่ายในการสื่อสารกับเครื่องกับเครื่อง
FlexFetcher สร้างขึ้นสำหรับแพลตฟอร์มถัดไป:
หมายความว่าคุณสามารถใช้งานได้ทั้งใน. NET Core (ดู samples/WebApiSample ) และ. NET Framework (ดู samples/WebApiSample.Framework48 ) โครงการ
FlexFetcher รองรับประเภทข้อมูลถัดไปสำหรับฟิลด์ที่ใช้ในตัวกรองและตัวเรียงลำดับ:
ค่าทั้งหมดอาจเป็นโมฆะ
คุณสามารถติดตั้ง FlexFetcher (NUGET) ผ่าน NUGET Package Manager Console โดยเรียกใช้คำสั่งถัดไป:
dotnet add package FlexFetcher
ในการติดตั้ง flexfetcher.dependencyinject.microsoft (NUGET):
dotnet add package FlexFetcher.DependencyInjection.Microsoft
ในการติดตั้ง flexfetcher.serialization.newtonsoftjson (Nuget):
dotnet add package FlexFetcher.Serialization.NewtonsoftJson
ในการติดตั้ง flexfetcher.serialization.systemtextjson (NuGet):
dotnet add package FlexFetcher.Serialization.SystemTextJson
ตัวอย่างทั้งหมดทำในชุดข้อมูลทดสอบซึ่งกำหนดไว้ใน
tests/TestData/InMemoryDataHelper.csและประกอบด้วยtests/TestData/Database/PeopleEntity.csและtests/TestData/Database/AddressEntity.cs
วิธีที่ง่ายที่สุดในการใช้ FlexFetcher คือการใช้วิธีการขยายสำหรับอินเทอร์เฟซ IQueryable<T> และ IEnumerable<T>
var filter = new DataFilter
{
Filters = new List < DataFilter >
{
new ( )
{
Field = "Name" ,
Operator = DataFilterOperator . Equal ,
Value = "John"
}
}
} ;
var result = _ctx . People . FilterData ( filter ) . ToList ( ) ; var sorter = new DataSorters
{
Sorters = new List < DataSorter >
{
new DataSorter // First sort by Surname in ascending order
{
Field = "Surname" ,
Direction = DataSorterDirection . Asc
} ,
new DataSorter // Then sort by Name in descending order
{
Field = "Name" ,
Direction = DataSorterDirection . Desc
}
}
} ;
var result = _ctx . People . SortData ( sorter ) . ToList ( ) ; var pager = new DataPager { PageSize = 3 , Page = 1 } ; // Numeration starts from 1 for Page number
OR
var pager = new DataPager { Skip = 3 , Take = 3 } ;
var result = _ctx . People . PageData ( pager ) . ToList ( ) ; วิธีการขยายเป็นสิ่งที่ดีสำหรับกรณีง่าย ๆ แต่การใช้งานของพวกเขามี จำกัด มาก
สำหรับกรณีที่ซับซ้อนมากขึ้นคุณสามารถใช้คลาส FlexFetcher : FlexFilter<TEntity> และ FlexFilter<TEntity, TModel> FlexSorter<TEntity, TModel> , FlexSorter<TEntity> FlexPager<TEntity> และ FlexPager<TEntity, TModel> , FlexFetcher<TEntity, TModel> FlexFetcher<TEntity>
แม้ว่าจะไม่ได้แนะนำวิธี แต่เพื่อความชัดเจนเรามาดูวิธีการสร้างกรณีของชั้นเรียนด้วยตนเอง เราจะดูการฉีดพึ่งพาในส่วนที่สอดคล้องกันในภายหลัง
var filter = new DataFilter
{
Filters = new List < DataFilter >
{
new ( )
{
Field = "Name" ,
Operator = DataFilterOperator . Equal ,
Value = "John"
}
}
} ;
var flexFilter = new FlexFilter < PeopleEntity > ( ) ;
var result = flexFilter . FilterData ( _ctx . People , filter ) . ToList ( ) ; var sorters = new DataSorters
{
Sorters = new List < DataSorter >
{
new DataSorter
{
Field = "Surname" ,
Direction = DataSorterDirection . Asc
}
}
} ;
var flexSorter = new FlexSorter < PeopleEntity > ( ) ;
var result = flexSorter . SortData ( _ctx . People , sorters ) . ToList ( ) ; var pager = new DataPager { PageSize = 3 , Page = 1 } ;
var flexPager = new FlexPager < PeopleEntity > ( ) ;
var result = flexPager . PageData ( _ctx . People , pager ) . ToList ( ) ; var pager = new DataPager { PageSize = 3 , Page = 1 } ;
var flexFetcher = new FlexFetcher < PeopleEntity > ( ) ;
var result = flexFetcher . FetchData ( _ctx . People , null , null , pager ) . ToList ( ) ; // Filter, sorter and pager parameters are optional ในการใช้ FlexFetcher ด้วยการฉีดพึ่งพาอย่าลืมติดตั้ง FlexFetcher.DependencyInjection.Microsoft แพ็คเกจ
เป็นไปได้ที่จะฉีดคลาส Flexfetcher หลักเช่นเดียวกับส่วนประกอบ: Flexfilter, Flexsorter, Flexpager การใช้งานขั้นพื้นฐานคือ:
services . AddSingleton < FlexFetcher < PeopleEntity > > ( ) ;คลาส Flexfetcher ไม่มีสถานะใด ๆ ดังนั้นจึงปลอดภัยที่จะใช้เป็นซิงเกิล แต่ถ้าคุณต้องการใช้เป็นขอบเขตหรือชั่วคราวมันก็ขึ้นอยู่กับคุณ
การเติมเต็มสถานการณ์ขั้นสูงจะแสดงต่อไป ดูตัวอย่างเพิ่มเติมใน tests/FlexFetcherTests/DependencyInjectionTests/ServiceProviderTests.cs , samples/WebApiSample ) และ samples/WebApiSample.Framework48
ในตัวอย่างข้อมูลข้อมูลของเราเรามีวัตถุซ้อนกัน: PeopleEntity มีคุณสมบัติที่อยู่ มาดูวิธีการกรองโดยวัตถุซ้อนกัน:
var filter = new DataFilter
{
Filters = new List < DataFilter >
{
new ( )
{
Field = "Address.City" , // Address is a nested object, so we use dot notation
Operator = DataFilterOperator . Equal ,
Value = "New York"
}
}
} ;
var flexAddressFilter = new FlexFilter < AddressEntity > ( ) ;
var peopleFilterOptions = new FlexFilterOptions < PeopleEntity > ( ) ;
peopleFilterOptions . AddNestedFlexFilter ( flexAddressFilter ) ;
var flexPeopleFilter = new FlexFilter < PeopleEntity > ( peopleFilterOptions ) ;
var result = flexPeopleFilter . FilterData ( _ctx . People , filter ) . ToList ( ) ;สิ่งเดียวกันสามารถทำได้ด้วยการฉีดพึ่งพา:
Services . AddSingleton < FlexFilter < AddressEntity > > ( ) ;
Services . AddSingletonFlexOptions < FlexFilterOptions < PeopleEntity > > ( ( provider , options ) =>
{
options . AddNestedFlexFilter ( provider . GetRequiredService < FlexFilter < AddressEntity > > ( ) ) ;
} ) ;
Services . AddSingleton < FlexFilter < PeopleEntity > > ( ) ;หลักการเดียวกันนี้สามารถนำไปใช้กับ flexsorter, flexpager และ flexfetcher
ดูตัวอย่างเพิ่มเติมใน tests/FlexFetcherTests/DependencyInjectionTests/ServiceProviderTests.cs และ samples/WebApiSample
ในตัวอย่างก่อนหน้านี้เราใช้ตัวกรองเพียงตัวเดียว แต่เป็นไปได้ที่จะใช้ตัวกรองหลายตัวที่มีหรือหรือและ logics เช่นนี้:
var filter = new DataFilter
{
Logic = DataFilterLogic . Or ,
Filters = new List < DataFilter >
{
new ( )
{
Field = "Name" ,
Operator = DataFilterOperator . Equal ,
Value = "John"
} ,
new ( )
{
Logic = DataFilterLogic . And ,
Filters = new List < DataFilter >
{
new ( )
{
Field = "Name" ,
Operator = DataFilterOperator . Equal ,
Value = "Jane"
} ,
new ( )
{
Field = "Age" ,
Operator = DataFilterOperator . GreaterThan ,
Value = 55
}
}
}
}
} ;FlexFilter รองรับตัวกรองซ้อนกันด้วยความลึกใด ๆ
หากไม่ได้ระบุตรรกะจะถูกตั้งค่าเป็นและโดยค่าเริ่มต้น
ตัวกรองสามารถมีคุณสมบัติ (ตัวกรองและตรรกะ) หรือ (ฟิลด์, ผู้ประกอบการและค่า) คุณสมบัติ แต่ไม่ใช่ทั้งสองอย่าง
เราได้เห็นตัวอย่างที่มีผู้ให้บริการที่เท่าเทียมกันมากขึ้น แต่มีผู้ให้บริการมากขึ้น:
new DataFilter { Field = "Name" , Operator = DataFilterOperator . Equal , Value = "John" } new DataFilter { Field = "Name" , Operator = DataFilterOperator . NotEqual , Value = "John" } new DataFilter { Field = "Age" , Operator = DataFilterOperator . GreaterThan , Value = 55 } new DataFilter { Field = "Age" , Operator = DataFilterOperator . GreaterThanOrEqual , Value = 55 } new DataFilter { Field = "Age" , Operator = DataFilterOperator . LessThan , Value = 55 } new DataFilter { Field = "Age" , Operator = DataFilterOperator . LessThanOrEqual , Value = 55 } new DataFilter { Field = "Name" , Operator = DataFilterOperator . Contains , Value = "Jo" } new DataFilter { Field = "Name" , Operator = DataFilterOperator . StartsWith , Value = "Jo" } new DataFilter { Field = "Name" , Operator = DataFilterOperator . EndsWith , Value = "hn" } new DataFilter { Field = "Age" , Operator = DataFilterOperator . In , Value = new List < int > { 55 , 56 , 57 } } เพื่อสร้างตัวกรองตัวกรองของตัวเองจำเป็นต้องมี:
BaseFilterExpressionHandlerFilterExpressionBuilderAddCustomExpressionHandlers วิธีการในคลาส FilterExpressionBuilder ที่กำหนดเอง มันอาจมีลักษณะเช่นนี้ (ดู tests/FlexFetcherTests/FlexFilterTests/CustomFilterExpressionBuilderTests.cs ):
class CustomExpressionBuilderWithValueTest : FilterExpressionBuilder < PeopleEntity >
{
protected override void AddCustomExpressionHandlers ( List < IFilterExpressionHandler > handlers )
{
handlers . Add ( new ModuleFilterExpressionHandler ( ) ) ;
}
private class ModuleFilterExpressionHandler : BaseFilterExpressionHandler
{
public override string Operator => "MODULE" ;
public override Expression BuildExpression ( Expression property , DataFilter filter )
{
var value = BuildValueExpression ( filter ) ;
return Expression . Equal ( Expression . Modulo ( property , value ) , Expression . Constant ( 0 ) ) ;
}
}
}
var customExpressionBuilder = new CustomExpressionBuilderWithValueTest ( ) ;
var options = new FlexFilterOptions < PeopleEntity > ( customExpressionBuilder ) ;
var flexFilter = new FlexFilter < PeopleEntity > ( options ) ;
var filter = new DataFilter
{
Logic = DataFilterLogic . And ,
Filters = new List < DataFilter >
{
new ( )
{
Field = "Age" ,
Operator = "Module" ,
Value = 15
}
}
} ;
var result = flexFilter . FilterData ( _ctx . People , filter ) . ToList ( ) ;นอกจากนี้ยังเป็นไปได้ที่จะสร้างตัวกรองตัวกรองที่กำหนดเองซึ่งต้องการค่าทั้งหมด:
class CustomExpressionBuilderWithoutValueTest : FilterExpressionBuilder < PeopleEntity >
{
protected override void AddCustomExpressionHandlers ( List < IFilterExpressionHandler > handlers )
{
handlers . Add ( new EvenNumberFilterExpressionHandler ( ) ) ;
}
private class EvenNumberFilterExpressionHandler : BaseFilterExpressionHandler
{
public override string Operator => "EVEN" ;
public override Expression BuildExpression ( Expression property , DataFilter filter )
{
return Expression . Equal ( Expression . Modulo ( property , Expression . Constant ( 2 , property . Type ) ) , Expression . Constant ( 0 ) ) ;
}
}
}
var customExpressionBuilder = new CustomExpressionBuilderWithoutValueTest ( ) ;
var options = new FlexFilterOptions < PeopleEntity > ( customExpressionBuilder ) ;
var flexFilter = new FlexFilter < PeopleEntity > ( options ) ;
var filter = new DataFilter
{
Logic = DataFilterLogic . And ,
Filters = new List < DataFilter >
{
new ( )
{
Field = "Age" ,
Operator = "Even" ,
Value = null
}
}
} ;
var result = flexFilter . FilterData ( _ctx . People , filter ) . ToList ( ) ; การใช้งานที่มีการฉีดพึ่งพาอาจมีลักษณะเช่นนี้ (ดู tests/FlexFetcherTests/DependencyInjectionTests/ServiceProviderTests.cs , GenericFlexFilterWithExpressionBuilderUsage() ): วิธีการ):
class CustomExpressionBuilder : FilterExpressionBuilder < PeopleEntity > ;
class GenericFlexFilterService ( FlexFilter < PeopleEntity > flexFilter )
{
public FlexFilter < PeopleEntity > FlexFilter { get ; } = flexFilter ;
}
var serviceCollection = new ServiceCollection ( ) ;
serviceCollection . AddSingleton < FilterExpressionBuilder < PeopleEntity > , CustomExpressionBuilder > ( ) ;
serviceCollection . AddSingleton < FlexFilterOptions < PeopleEntity > > ( ) ;
serviceCollection . AddSingleton < FlexFilter < PeopleEntity > > ( ) ;
serviceCollection . AddTransient < GenericFlexFilterService > ( ) ;
var serviceProvider = serviceCollection . BuildServiceProvider ( ) ;
var testInstance = serviceProvider . GetRequiredService < GenericFlexFilterService > ( ) ; ที่นี่ CustomExpressionBuilder เป็นตัวสร้างนิพจน์ตัวกรองที่กำหนดเองซึ่งส่งผ่านไปยังตัวสร้าง FlexFilterOptions จากนั้น FlexFilterOptions จะถูกส่งผ่านไปยังตัวสร้าง FlexFilter ในที่สุด FlexFilter จะถูกฉีดเข้าไปในคลาส GenericFlexFilterService
มันอาจดูซับซ้อนเล็กน้อย แต่มันค่อนข้างทรงพลัง Flexfetcher มีความยืดหยุ่นมาก
ในตัวอย่างก่อนหน้านี้เราใช้ชื่อฟิลด์เหมือนอยู่ในเอนทิตี แต่เป็นไปได้ที่จะใช้ชื่อฟิลด์ที่กำหนดเอง มีสองวิธีในการทำ:
วิธีที่ง่ายที่สุดคือการกำหนดนามแฝงของฟิลด์เป็นสตริง:
// Manual creation of FlexFilter
var addressFilterOptions = new FlexFilterOptions < AddressEntity > ( ) ;
addressFilterOptions . Field ( entity => entity . City ) . Map ( "Town" ) ;
FlexFilter < AddressEntity > addressFilter = new FlexFilter < AddressEntity > ( addressFilterOptions ) ;
// Dependency injection of FlexFetcher
Services . AddSingletonFlexOptions < FlexFetcherOptions < AddressEntity > > ( options =>
{
options . Field ( entity => entity . City ) . Map ( "Town" ) ;
} ) ;
Services . AddSingleton < FlexFetcher < AddressEntity > > ( ) ;ในตัวอย่างนี้เราทำแผนที่ที่อยู่อาศัยคุณสมบัติของเมืองไปยังสนาม "เมือง" เช่นเราสามารถใช้ "เมือง" ในตัวกรองและตัวเรียงลำดับแทน "เมือง"
สิ่งเดียวกันสามารถทำได้ด้วยคุณสมบัติของคลาสรุ่น:
public class AddressModel
{
public string Town { get ; set ; }
}
// Manual creation of FlexFilter
var addressFilterOptions = new FlexFilterOptions < AddressEntity , AddressModel > ( ) ;
addressFilterOptions . Field ( entity => entity . City ) . Map ( model => model . Town ) ;
FlexFilter < AddressEntity , AddressModel > addressFilter = new FlexFilter < AddressEntity , AddressModel > ( addressFilterOptions ) ;
// Dependency injection of FlexFetcher
Services . AddSingletonFlexOptions < FlexFetcherOptions < AddressEntity , AddressModel > > ( options =>
{
options . Field ( entity => entity . City ) . Map ( model => model . Town ) ;
} ) ;
Services . AddSingleton < FlexFetcher < AddressEntity , AddressModel > > ( ) ;ในตัวอย่างนี้เราแมปคุณสมบัติของ addressEntity.city ไปยังที่อยู่ที่อยู่อาศัย. town โดยทั่วไปแล้วมันให้ความเป็นไปได้ในการแมปโมเดลมุมมองไปยังเอนทิตีและมีการแมปที่แตกต่างกันสำหรับโมเดลมุมมองที่แตกต่างกัน
อนุญาตให้แมปหลายครั้งได้ดังนั้นจึงเป็นไปได้ที่จะแมปฟิลด์เอนทิตีหนึ่งรายการกับนามแฝงหลายรายการตัวอย่างเช่น:
options . Field ( entity => entity . City ) . Map ( "Town" ) . Map ( "CityName" ) ;
ได้รับอนุญาตให้แมปเพื่อดูคุณสมบัติของโมเดลและค่าสตริงในเวลาเดียวกัน:
options . Field ( x => x . City ) . Map ( model => model . Town ) . Map ( "CityName" ) ;
อนุญาตให้ทำแผนที่ไปยังฟิลด์ที่กำหนดเอง (ดูด้านล่าง) ได้:
var customField = new PeopleFullNameCustomField ( ) ; var options = new FlexSorterOptions < PeopleEntity > ( ) ; options . AddCustomField ( customField ) . Map ( "Title" ) ; var flexSorter = new FlexSorter < PeopleEntity > ( options ) ;
ในตัวอย่างก่อนหน้านี้เราใช้คุณสมบัติของเอนทิตีเท่านั้น แต่เป็นไปได้ที่จะใช้ฟิลด์ที่กำหนดเองกับนิพจน์ที่กำหนดเอง
พวกเขาอาจใช้ใน flexsorters, flexfilters, flexfetchers
สมมติว่าเราต้องการเพิ่มฟิลด์ "FullName" ที่กำหนดเองให้กับ PeopleEntity:
public class PeopleFullNameCustomField : BaseFlexCustomField < PeopleEntity , string > // string is a type of field
{
public override string Field => "FullName" ;
protected override Expression < Func < PeopleEntity , string > > BuildFieldExpression ( IFlexFetcherContext ? context = null )
{
return p => p . Surname + " " + p . Name ;
}
}
// Manual creation of FlexSorter
var customField = new PeopleFullNameCustomField ( ) ;
var options = new FlexSorterOptions < PeopleEntity > ( ) ;
options . AddCustomField ( customField ) . Map ( "Title" ) ;
var flexSorter = new FlexSorter < PeopleEntity > ( options ) ;
// Dependency injection of FlexFetcher
Services . AddSingletonFlexOptions < FlexFetcherOptions < PeopleEntity > > ( options =>
{
options . AddCustomField ( new PeopleFullNameCustomField ( ) ) . Map ( "Title" ) ; // Map is optional
} ) ;
Services . AddSingleton < FlexFetcher < PeopleEntity > > ( ) ; ในกรณีส่วนใหญ่ฟิลด์ที่กำหนดเองที่เราเห็นในส่วนก่อนหน้านั้นเพียงพอ แต่บางครั้งก็จำเป็นต้องมีฟิลด์ที่กำหนดเองพร้อมนิพจน์ที่กำหนดเองในตัวกรองสำหรับตรรกะตัวกรองที่ซับซ้อนมากขึ้น
สมมติว่าเราต้องการเพิ่มฟิลด์ "กลุ่มคน" ที่กำหนดเองให้กับผู้คนและใช้ตัวกรอง "AnyGroup" ลงไป:
public class PeopleWithManyToManyGroupsCustomFilter : BaseFlexCustomFieldFilter < PeopleEntity >
{
public override string Field => "PeopleGroups" ;
protected override Expression < Func < PeopleEntity , bool > > BuildFilterExpression ( string filterOperator , object ? filterValue ,
IFlexFetcherContext ? context = null )
{
string value = ( string ) filterValue ! ;
return filterOperator switch
{
"AnyGroup" => p => p . PeopleGroups . Any ( pg => pg . Group ! . Name == value ) ,
_ => throw new NotSupportedException ( $ "Invalid filter operator: { filterOperator } " )
} ;
}
}
// Another way to create extended FlexFilter - custom class inherrited from FlexFilter
public class PeopleWithManyToManyGroups : FlexFilter < PeopleEntity >
{
public PeopleWithManyToManyGroups ( PeopleWithManyToManyGroupsCustomFilter customFilter )
{
Options . AddCustomField ( customFilter ) ;
}
}
var customFilter = new PeopleWithManyToManyGroupsCustomFilter ( ) ;
var peopleFilter = new PeopleWithManyToManyGroups ( customFilter ) ; บริบท FlexFetcher เป็นวัตถุพิเศษที่ส่งผ่านไปยังฟิลด์ที่กำหนดเองและตัวกรองที่กำหนดเอง
สามารถมีข้อมูลใด ๆ ที่จำเป็นสำหรับฟิลด์ที่กำหนดเองและตัวกรองที่กำหนดเอง
สมมติว่าเราต้องเลือกสาขาเอนทิตีที่แตกต่างกันขึ้นอยู่กับวัฒนธรรม:
public class CustomContext : IFlexFetcherContext // Create your own context class
{
public CultureInfo Culture { get ; set ; } = null ! ;
}
public class PeopleOriginCountryCustomField : BaseFlexCustomField < PeopleEntity , string ? >
{
public override string Field => "Country" ;
protected override Expression < Func < PeopleEntity , string ? > > BuildFieldExpression ( IFlexFetcherContext ? context = null )
{
if ( context is not CustomContext customContext )
{
throw new NotSupportedException ( "Invalid context type" ) ;
}
if ( customContext . Culture . Name == "de-DE" )
{
return entity => entity . OriginCountryDe ;
}
return entity => entity . OriginCountryEn ;
}
}
var customExpressionFilter = new PeopleOriginCountryCustomField ( ) ;
var options = new FlexFilterOptions < PeopleEntity > ( ) ;
options . AddCustomField ( customExpressionFilter ) ;
var flexFilter = new FlexFilter < PeopleEntity > ( options ) ;
var filter = new DataFilter
{
Filters = new List < DataFilter >
{
new ( )
{
Field = "Country" ,
Operator = DataFilterOperator . Equal ,
Value = "Deutschland"
}
}
} ;
var context = new CustomContext
{
Culture = new CultureInfo ( "de-DE" )
} ;
var result = flexFilter . FilterData ( _ctx . People , filter , context ) . ToList ( ) ; ในส่วนก่อนหน้านี้เราได้เห็นวิธีการทำงานกับฟิลด์และวิธีการทำแผนที่ โดยค่าเริ่มต้นฟิลด์ทั้งหมดสามารถมองเห็นได้และสามารถใช้ในตัวกรองและตัวเรียงลำดับ แต่ในบางกรณีจำเป็นต้องซ่อนบางฟิลด์จากการใช้ในตัวกรองและตัวเรียงลำดับ
มีสองวิธีในการซ่อนฟิลด์:
วิธีการกำหนดเขตข้อมูลที่ซ่อนอยู่:
var options = new FlexFilterOptions < PeopleEntity > ( ) ;
options . Field ( x => x . CreatedByUserId ) . Hide ( ) ; // CreatedByUserId is a hidden field, it can't be used in filters and sorters
var flexFilter = new FlexFilter < PeopleEntity > ( options ) ;วิธีการกำหนดเขตข้อมูลทั้งหมดที่ซ่อนอยู่:
var options = new FlexFilterOptions < PeopleEntity > ( ) ;
options . HideOriginalFields ( ) ;
var flexFilter = new FlexFilter < PeopleEntity > ( options ) ;นามแฝงของฟิลด์จะไม่ได้รับผลกระทบจากการซ่อนดังนั้นพวกเขาจึงสามารถใช้ในตัวกรองและตัวเรียงลำดับแม้ว่าจะซ่อนฟิลด์ดั้งเดิม
เขตข้อมูลที่กำหนดเองอาจถูกซ่อนไว้:
class SimplePeopleSorterWithCustomSorter : FlexSorter < PeopleEntity >
{
public SimplePeopleSorterWithCustomSorter ( )
{
Options . AddCustomField ( new PeopleFullNameCustomField ( ) ) . Map ( "Title" ) . Hide ( ) ;
}
}ฟิลด์ที่กำหนดเองจะไม่ถูกซ่อนไว้โดยอัตโนมัติเมื่อใช้ hideoriginalfields () ดังนั้นควรซ่อนด้วยตนเองหากจำเป็น
FlexFetcher ได้รับการออกแบบให้ใช้ในการสื่อสารแบบเครื่องกับเครื่องจักรดังนั้นจึงเป็นเรื่องสำคัญที่จะต้องสามารถทำให้เป็นอนุกรมและค้นหาแบบสอบถามได้
ในกรณีง่ายๆ JSON serializer ใด ๆ สามารถใช้งานได้ แต่เป็น Soos ตามที่คุณต้องการใช้ฟิลด์ที่มีประเภทเวลาเพียงอย่างเดียวหรือคุณจำเป็นต้องทำให้เป็นอนุกรม/deserialize อาร์เรย์เพื่อใช้ In ตัวดำเนินการคุณต้องใช้การตั้งค่าและตัวแปลง JSON ที่ FlexFetcher.Serialization.SystemTextJson เองจาก FlexFetcher.Serialization.NewtonsoftJson
ติดตั้งแพ็คเกจ FlexFetcher.Serialization.NewtonsoftJson และรับการตั้งค่าจากคลาส Helper:
var jsonSettings = NewtonsoftHelper . GetSerializerSettings ( ) ;
var json = JsonConvert . SerializeObject ( filter , jsonSettings ) ;
var deserializedFilter = JsonConvert . DeserializeObject < DataFilter > ( json , jsonSettings ) ; ติดตั้ง FlexFetcher.Serialization.SystemTextJson แพ็คเกจและรับการตั้งค่าจากคลาส Helper:
var jsonSettings = SystemTextJsonHelper . GetSerializerOptions ( ) ;
var json = JsonSerializer . Serialize ( filter , jsonSettings ) ;
var deserializedFilter = JsonSerializer . Deserialize < DataFilter > ( json , jsonSettings ) ;นอกจากนี้ยังมีตัวแปลง JSON ที่อนุญาตให้ serialize/deserialize วัตถุไปที่/จาก JSON ในรูปแบบสรุปเช่นนี้ (ตัวอย่าง dataFilter):
{
"L" : " And " ,
"Fs" : [
{
"O" : " Eq " ,
"F" : " Address.Town " ,
"V" : " New York "
}
]
} ดูตัวอย่างเพิ่มเติมของรูปแบบที่กระชับใน tests/FlexFetcherTests/SerializationTests/NewtonsoftTests.cs และ tests/FlexFetcherTests/SerializationTests/SystemTextJsonTests.cs และใน samples/WebApiSample และ samples/WebApiSample.Framework48
เพื่อรองรับรูปแบบที่กระชับจำเป็นต้องใช้ตัวแปลงถัดไปจาก FlexFetcher.Serialization.NewtonsoftJson และ FlexFetcher.Serialization.SystemTextJson ตาม:
FlexFetcherDataSorterConverterFlexFetcherDataSortersConverterFlexFetcherDataPagerConverterFlexFetcherDataFilterConverterFlexFetcherDataQueryConverter ตัวแปลงทั้งหมดมีพารามิเตอร์ readOnlyShortForm constructor หากตั้งค่าเป็นจริงแล้วรูปแบบที่กระชับจะได้รับอนุญาตสำหรับการ deserialization มิฉะนั้นจะอนุญาตให้มีรูปแบบทั้งแบบเต็มและกระชับ
โดยทั่วไปไม่จำเป็นต้องใช้ readOnlyShortForm ในกรณีส่วนใหญ่ แต่ถ้าคุณต้องการ จำกัด deserialization ในรูปแบบที่กระชับเท่านั้นคุณสามารถตั้งค่าเป็นจริง
FlexFetcher สามารถใช้ในโครงการ ASP.NET ทั้ง Core และ Framework แต่การกำหนดค่า serializers นั้นแตกต่างกัน
ขั้นตอนต่อไปจำเป็นต้องกำหนดค่าอนุกรมในโครงการหลักของ ASP.NET (ตัวอย่างสำหรับ System.Text.json):
FlexFetcherModelBinderFlexFetcherModelBinderProviderAddControllers ใน Program.cs เช่นนี้: builder . Services . AddControllers ( options =>
{
options . ModelBinderProviders . Insert ( 0 , new FlexFetcherModelBinderProvider ( ) ) ;
} )
. AddJsonOptions ( options =>
{
options . JsonSerializerOptions . Converters . Add ( new GenericConverter ( ) ) ;
// Next converters are optional, but they are needed to support succinct format
options . JsonSerializerOptions . Converters . Add ( new FlexFetcherDataSorterConverter ( ) ) ;
options . JsonSerializerOptions . Converters . Add ( new FlexFetcherDataSortersConverter ( ) ) ;
options . JsonSerializerOptions . Converters . Add ( new FlexFetcherDataPagerConverter ( ) ) ;
options . JsonSerializerOptions . Converters . Add ( new FlexFetcherDataFilterConverter ( ) ) ;
options . JsonSerializerOptions . Converters . Add ( new FlexFetcherDataQueryConverter ( ) ) ;
} ) ; ดูรหัสใน samples/WebApiSample
ขั้นตอนต่อไปจำเป็นต้องกำหนดค่าอนุกรมในโครงการ ASP.NET Framework (ตัวอย่างสำหรับ newtonsoft.json):
FlexFetcherModelBinderFlexFetcherModelBinderProviderWebApiConfig.cs เช่นนี้: var jsonSettings = NewtonsoftHelper . GetSerializerSettings ( ) ;
config . Formatters . JsonFormatter . SerializerSettings = jsonSettings ;
// Next converters are optional, but they are needed to support succinct format
config . Formatters . JsonFormatter . SerializerSettings . Converters . Add ( new FlexFetcherDataFilterConverter ( ) ) ;
config . Formatters . JsonFormatter . SerializerSettings . Converters . Add ( new FlexFetcherDataSortersConverter ( ) ) ;
config . Formatters . JsonFormatter . SerializerSettings . Converters . Add ( new FlexFetcherDataSorterConverter ( ) ) ;
config . Formatters . JsonFormatter . SerializerSettings . Converters . Add ( new FlexFetcherDataPagerConverter ( ) ) ;
config . Formatters . JsonFormatter . SerializerSettings . Converters . Add ( new FlexFetcherDataQueryConverter ( ) ) ;
config . Services . Insert ( typeof ( ModelBinderProvider ) , 0 , new FlexFetcherModelBinderProvider ( ) ) ; ดูรหัสใน samples/WebApiSample.Framework48
มีสองโครงการตัวอย่างในที่เก็บ:
samples/WebApiSample - โครงการ ASP.NET Core Web APIsamples/WebApiSample.Framework48 - ASP.NET Framework 4.8 Web API Projectทั้งสองโครงการมีฟังก์ชั่นเดียวกันและสาธิตวิธีการใช้ FlexFetcher ในโครงการ ASP.NET
เพียงแค่สร้างและเรียกใช้เพื่อดูว่า FlexFetcher ทำงานอย่างไรในโครงการจริง ใช้ไคลเอนต์ REST ที่คุณชื่นชอบเพื่อส่งคำขอไปยัง API ตัวอย่างของคำขอสามารถพบได้ใน samples/WebApiSample/ReadMe.md และ samples/WebApiSample.Framework48/ReadMe.md
นอกจากนี้ยังมีการทดสอบในโฟลเดอร์ tests/FlexFetcherTests ซึ่งแสดงให้เห็นถึงวิธีการใช้ FlexFetcher ในสถานการณ์ที่แตกต่างกัน