مقایسه EF Core و دیگر Micro-ORM

در توسعه وب اپلیکیشن ها با استفاده از ASP.NET Core گزینه مناسب برای پیاده سازی کدهای دسترسی به داده Entity Framework Core می باشد. البته علیرغم اینکه بسیاری از موضوعات کار کردن با دیتابیس ها و البته کپسوله کردن جزئیات مربوط به این عملیات توسط Entity Framework Core از دید برنامه نویسان مخفی می شود گزینه های دیگری نیز وجود دارند که می‌توانند علاوه بر Entity Framework Core مورد بررسی و استفاده قرار بگیرند. یک گزینه open-source و بسیار معروف Dapper است که تحت عنوان یک micro-ORM شناخته می‌شود. در واقع یک micro-ORM یک ابزار است که به صورت سبک وزن و با قابلیت کمتری پیاده سازی شده است و عملیات نگاشت کردن آبجکت ها به data structure های مربوط به بانک اطلاعاتی را انجام می‌دهد. Dapper به عنوان یک ORM هدف خود را بر روی افزایش Performance قرار داده است و تمرکز کمتری در رابطه با کپسوله کردن کوئری هایی که برای بازیابی کردن و به روزرسانی کردن داده ها استفاده می کند قرار می دهد. از آنجایی که SQL تعریف شده توسط Dapper از دید برنامه نویس مخفی نمی ماند با استفاده از Dapper می توانیم به سادگی کوئری های مورد نظر خود را به طور دقیق و سفارشی پیاده سازی کرده و آنها را برای اجرا شدن به سمت دیتابیس ارسال کنیم.فریم ورک Entity Framework Core دو ویژگی منحصر به فرد دارد که آن را از Dapper بسیار متمایز کرده و البته بر روی Performance آن تاثیر کمی منفی نیز خواهد گذاشت. اولین ویژگی ترجمه شدن خودکار دستورات LINQ به دستورات متناظر SQL به منظور اجرا شدن در دیتابیس میباشند. این جملات هرچند که در حافظه کش قرار می‌گیرند اما در اولین اجرا شدن دچار سرباری می‌شوند که بر روی Performance برنامه نیز تأثیر منفی خواهد گذاشت. ویژگی دوم Entity Framework Core ردگیری کردن Entity ها توسط Change tracker می باشد که این موضوع باعث می‌شود جملات Update برای بروز رسانی کردن رکوردهای دیتابیس با سرعت و بهینگی بالاتری تولید بشوند. البته می‌توان برای برخی از کوئری های ارسال شده به سمت دیتابیس از یک Extension method به نام AsNotTracking استفاده کرد تا Entity های بازیابی شده از دیتابیس ردگیری نشوند. علاوه بر این موضوع Entity Framework اغلب دستورات SQL خود را با بهینه سازی کامل ایجاد کرده و از این لحاظ Performance بسیار بالایی را نیز خواهند داشت. اگر برنامه‌نویس تمایل به داشتن کنترل بیشتری بر روی جملات ارسال شده به سمت دیتابیس داشته باشد می‌تواند از دستورات سفارشی و خام SQL و یا procedure stored های تعریف شده در دیتابیس استفاده کرده و با لحاظ کردن آنها در Entity Framework Core سرعت برنامه را افزایش بدهد. از این نقطه نظر Dapper از لحاظ کارایی از Entity Framework Core بهتر عمل می‌کند. اما این Performance بالا خیلی چشمگیر نیست و می‌توان در سناریو هایی از آن چشم پوشی کرد. ضمنا برای بررسی و مقایسه Syntax مربوط به کار کردن با Dapper و Entity Framework Core میتوان کد زیر را بررسی نمود.// EF Core privatereadonly CatalogContext _context;public async Task &amp;amp;lt; IEnumerable &amp;amp;lt; CatalogType &amp;amp;gt;&amp;amp;gt; GetCatalogTypes() {return await _context.CatalogTypes.ToListAsync();}// Dapperprivate readonly SqlConnection _conn;public async Task &amp;amp;lt; IEnumerable &amp;amp;lt; CatalogType &amp;amp;gt;&amp;amp;gt; GetCatalogTypesWithDapper() {return await _conn.QueryAsync &amp;amp;lt; CatalogType &amp;amp;gt; (&quot;SELECT * FROM CatalogType&quot;);}علاوه بر این موضوع اگر نیاز به ایجاد کردن object graphs های پیچیده تر با استفاده از Dapper دارید می‌توانید کوئری های مورد نظر خود را ایجاد کرده و به صورت سفارشی آنها را لحاظ نماید این موضوع در Entity Framework Core با استفاده از متد Include اتفاق می‌افتد. برای به دست آوردن داده ها با استفاده از Dapper ‌ گزینه های بیشتری نیز در پیش روی ما قرار گرفته اند. برای مثال قابلیت Multi Mapping در Dapper اجازه می‌دهد تا یک سطر در دیتابیس به چندین آپدیت مختلف نگاشت شود. برای مثال فرض کنید که یک کلاس به نام Post دارید که در آن یک پروپرتی به نام Owner از نوع یک کلاس به نام User تعریف شده است. کدی که در قسمت زیر مشاهده می کنید تمامی داده های مورد نیاز را برای ما برخواهد گرداند.select * from #Posts pleft join #Users u on u.Id = p.OwnerIdOrder by p.Idهر سطر برگردانده شده توسط دستور بالا هم شامل داده‌های مربوط به User می باشند و هم شامل داده‌های مربوط به Post است. از آنجایی که داده‌های مربوط به User می بایست به داده‌های مربوط به Post متصل بشود و این اتفاق از طریق پروپرتی Owner رخ می‌دهد یک تابع به شکل زیر نوشته خواهد شد.(post, user) =&gt; { post.Owner = user; return post; }علاوه بر این کد کامل برای برگرداندن مجموعه‌ای از Post ها به همراه پروپرتی Owner آنها و البته قرار داده شدن داده‌های مربوط به User در پروپرتی Owner شبیه به کد زیر خواهد بود.var sql = @&quot;select * from #Posts p left join #Users u on u.Id = p.OwnerId Order by p.Id&quot;;var data = connection.Query &lt; Post,User, Post &gt; (sql, (post, user) = &gt;{post.Owner = user;return post;});از آنجایی که سطح کپسوله کردن جزئیات مربوط به بانک اطلاعاتی در استفاده کردن از Dapper به مراتب کمتر از Entity Framework Core می باشد برنامه نویسان اغلب نیاز دارند که ساختار مربوط به ذخیره شدن داده ها در دیتابیس را بدانند تا بتوانند به بهترین شکل ممکن با آنها کار کنند و کدهای مناسبی را لحاظ نمایند. زمانی که Model برنامه تغییر می‌کند به جای ایجاد کردن یک migration جدید که یکی از قابلیت های Entity Framework Core است نیاز است که تک تک کوئری های نوشته شده با استفاده از Dapper به‌روزرسانی بشود. دقت کنید که این موضوع در مقایسه با Entity Framework Core که به صورت کاملا خودکار mapping های مربوط به کلاس ها را در DbContext به‌روزرسانی می‌کند کمی دردسر ساز خواهد شد. کوئری های نوشته شده با استفاده از Dapper در زمان کامپایل مشکلی نخواهند داشت اما این موضوع ممکن است که در زمان اجرا شدن برنامه، نرم‌افزار را دچار مشکل کند و کشف خطا های ایجاد شده را دشوارتر نمایند. در کنار این پیچیدگی‌ها Dapper با سرعت فوق العاده خود در کار کردن با بانک‌های اطلاعاتی گوی سبقت را از Entity Framework Core ربوده است.در بسیاری از نرم‌افزارها، تکنولوژی‌ Entity Framework Core با Performance قابل قبولی می تواند به عنوان گزینه اول کار کردن با بانک‌های اطلاعاتی مورد استفاده قرار بگیرد. بنابراین برنامه نویسان می توانند از ویژگی های منحصر به فرد Entity Framework Core از قبیل migration ها و change tracking و البته ترجمه شدن جملات LINQ به دستورات SQL بهره‌مند شوند. علاوه بر این موضوع اگر قرار است که یک کوئری با سرعت فوق العاده بالائی اجرا بشود می توانید به سادگی یک Stored procedure تعریف شده در دیتابیس را توسط Entity Framework Core اجرا نمایید.منبع:وبسایت پرووید