Mini Query Builder
مقدمه
در فاز قبل با SQL روی PostgreSQL و SQL Server کار کردید و دیدید یک نیاز بهظاهر یکسان، روی دو Database لزوما ً یک SQL یکسان نمیشود. همچنین این سوال مطرح شد: اگر ۱۰ تا Database دیگر هم اضافه شود چه؟
در دنیای واقعی این queryها معمولاً داخل کد ساخته میشوند.
اگر برای هر Database یک
string
جدا نگه دارید، نگهداری کد خیلی زود از کنترل خارج میشود.
در این فاز راهحل را میسازید: یک Query Builder مینیمال. یکبار منطق query را تعریف میکنید و با Compilerهای جدا، آن را به SQL مربوط به PostgreSQL یا SQL Server ترجمه میکنید؛ همان ایدهای که کتابخانههایی مثل SqlKata روی آن بنا شدهاند.
هدف ساخت کتابخانهٔ کامل صنعتی نیست.
کافی است نسخهٔ خیلی کوچک برای SELECT و چند شرط WHERE بسازید؛ ولی حتماً دو Compiler داشته باشید تا همان دردی که در فاز SQL دیدید را حل کند.
چرا Query Builder؟
قبل از کدنویسی، با همتیمیتان اینها را جمعبندی کنید:
- در فاز قبل برای یک منطق یکسان، SQL شما بین PostgreSQL و SQL Server کجاها فرق کرد؟
- اگر بخواهید شرطهای اختیاری را هم به query اضافه کنید، مدیریت رشتهٔ خام چقدر سخت میشود؟
- تفاوت placeholderها (
$1در برابر@p0) چه مشکلی برای کد مشترک ایجاد میکند؟
لطفاً قبل از فکر کردن به این سوالها سراغ پیادهسازی نروید.
برای آمادهسازی ذهنی:
الگوی Fluent Interface همان سبکی است که در LINQ و بسیاری از Query Builderها میبینید؛ متدها شیء را برمیگردانند تا بتوانید زنجیرهای صدا بزنید.
ایدهٔ Query Builder
یک Query Builder معمولاً دو بخش دارد:
- Query model
ساختار دادهای که میگوید از کدام Table، کدام Columnها، و با چه شرطهایی میخواهید بخوانید. - Compiler
بخشی که آن مدل را به رشتهٔ SQL و لیست bindings برای یک Database مشخص تبدیل میکند.
با این جداسازی، منطق query یکبار نوشته میشود و فقط Compiler عوض میشود.
برای آشنایی بیشتر:
تمرین اول: ساخت کلاس Query با Fluent API
یک
Class Library
با
#C
بسازید و کلاس
Query
را طوری پیاده کنید که حداقل این متدها را داشته باشد:
From(string table)Select(params string[] columns)Where(string column, object value)— فقط عملگر برابر (=)- هر متد باید خود
Queryرا برگرداند:
var query = new Query()
.From("Students")
.Select("Id", "Name")
.Where("IsMale", true)
.Where("Age", 20);
ت مرین دوم: دو Compiler
برای همان
Query
بالا، دو Compiler بنویسید:
PostgresCompilerSqlServerCompiler
هر کدام باید برگردانند:
- رشتهٔ SQL
- لیست bindings
AND
اینجا یک قابلیت جدا نیست که پیاده کنید.
فقط یعنی اگر دو بار
Where
صدا زدید، Compiler در رشتهٔ نهایی
SQL
شرطها را پشتسرهم با کلمهٔ
AND
میچسباند.
متد
And(...)
یا پشتیبانی از
OR
لازم نیست.