EF Code first هربار در حین آغاز اجرای برنامه و اولین کوئری که به بانک اطلاعاتی ارسال میکند، کار تشخیص روابط بین کلاسها و همچنین نگاشت آنها را به بانک اطلاعاتی، انجام میدهد. این مورد شاید با تعداد کم کلاسها آنچنان به نظر نرسد، اما اگر تعداد کلاسهای شما به بالای 200 عدد رسید، زمان آغاز برنامه آزار دهنده خواهد شد. راه حلی برای این مساله وجود دارد به نام ایجاد Viewهای متناظر با نگاشتها و سپس کامپایل آن به عنوان جزئی از برنامه، که در ادامه نحوه انجام اینکار را مرور خواهیم کرد.
بررسی ساختار pre-generated views
برای کامپایل نگاشتهای EF در خود برنامه (بجای تولید پویای هربار آنها)، ابتدا باید فایل edmx متناظر با مدلها و روابط بین آنها تشکیل شود:
پس از اینکه edmx تشکیل شد، باید از ساختار فشرده آن سه جزء زیر را استخراج کرد:
الف) ssdl : storageModels
ب) csdl : conceptualModels
ج) msl : mappings
اینکار را به صورت زیر میتوان انجام داد:
پس از آن باید محتوای این سه جزء را توسط متد Save هر کدام، در فایلهای xml ایی ذخیره کرد و توسط ابزاری به نام EdmGen.exe که جزئی از ویژوال استودیو است، فایل Context.Views.cs را تولید، به برنامه اضافه و سپس کامپایل کرد:
بهتر است این پروسه هر بار که قرار است ارائه نهایی برنامه صورت گیرد، انجام شود.
علاوه بر اینها اگر علاقمند باشید که کار فایل EdmGen را شبیه سازی کنید، کلاس زیر اینکار را انجام داده و قادر است خروجی vb یا cs متناظری را نیز تولید کند:
در اینجا همان مراحلی که عنوان شد، تکرار میشود. فایل edmx متناظر با وهلهای از DbContext برنامه، تولید شده و سه جزء آن استخراج میشوند. سپس این موارد به EntityViewGenerator موجود در اسمبلی System.Data.Entity.Design.dll ارسال شده و کد نهایی متناظر قابل کامپایل در برنامه تولید میگردد.
پس از تولید فایل Context.Views.cs یا Context.Views.vb، آنرا به پروژه اضافه کنید.
اینبار نحوه استفاده از آن باید به صورت زیر باشد:
از این جهت که تمام اطلاعات لازم جهت آغاز کار، در فایل تولیدی Context.Views وجود دارد و اکنون جزئی از فایل اجرایی برنامه است و نیازی به تکرار ساخت مجدد پویای آن نیست.
مرجع:
Entity Framework Code First View Generation Templates On Visual Studio Code Gallery
بررسی ساختار pre-generated views
برای کامپایل نگاشتهای EF در خود برنامه (بجای تولید پویای هربار آنها)، ابتدا باید فایل edmx متناظر با مدلها و روابط بین آنها تشکیل شود:
var ms = new MemoryStream(); using (var writer = XmlWriter.Create(ms)) { EdmxWriter.WriteEdmx(new Context(), writer); }
الف) ssdl : storageModels
ب) csdl : conceptualModels
ج) msl : mappings
اینکار را به صورت زیر میتوان انجام داد:
var xDoc = XDocument.Load(ms); var ssdl = xDoc.Descendants("{http://schemas.microsoft.com/ado/2009/02/edm/ssdl}Schema").Single(); var csdl = xDoc.Descendants("{http://schemas.microsoft.com/ado/2008/09/edm}Schema").Single(); var msl = xDoc.Descendants("{http://schemas.microsoft.com/ado/2008/09/mapping/cs}Mapping").Single();
EdmGen.exe /mode:ViewGeneration /incsdl:Context.csdl /inmsl:Context.msl /inssdl:Context.ssdl /outviews:Context.Views.cs
علاوه بر اینها اگر علاقمند باشید که کار فایل EdmGen را شبیه سازی کنید، کلاس زیر اینکار را انجام داده و قادر است خروجی vb یا cs متناظری را نیز تولید کند:
using System; using System.Data.Entity; using System.Data.Entity.Design; using System.Data.Entity.Infrastructure; using System.Data.Mapping; using System.Data.Metadata.Edm; using System.IO; using System.Linq; using System.Xml; using System.Xml.Linq; namespace EfUtils { public static class PreGeneratedViewsWriter { public static void CreatePreGeneratedViewsFile( this DbContext contextInstance, LanguageOption language = LanguageOption.GenerateCSharpCode, string viewsFile = "Context.Views.cs", string edmxFile = "context.edmx", string ssdlFile = "context.ssdl.xml", string csdlFile = "context.csdl.xml", string mslFile = "context.msl.xml") { using (var contextViewsMemoryStream = new MemoryStream()) { using (var edmxMemoryStream = new MemoryStream()) { var edmx = createEdmx(contextInstance, edmxFile, edmxMemoryStream); var mappingItemCollection = createMappingItemCollection(ssdlFile, csdlFile, mslFile, edmx); generateViews(language, viewsFile, contextViewsMemoryStream, mappingItemCollection); } } } private static void generateViews(LanguageOption language, string viewsFile, MemoryStream contextViewsMemoryStream, StorageMappingItemCollection mappingItemCollection) { var viewGenerator = new EntityViewGenerator // It's defined in System.Data.Entity.Design.dll { LanguageOption = language }; using (var streamWriter = new StreamWriter(contextViewsMemoryStream)) { var errors = viewGenerator.GenerateViews(mappingItemCollection, streamWriter).ToList(); if (errors.Any()) throw new InvalidOperationException(errors.First().Message); contextViewsMemoryStream.Position = 0; using (var reader = new StreamReader(contextViewsMemoryStream)) { var codeData = reader.ReadToEnd(); File.WriteAllText(viewsFile, codeData); } } } private static StorageMappingItemCollection createMappingItemCollection(string ssdlFile, string csdlFile, string mslFile, XDocument edmx) { var ssdl = edmx.Descendants("{http://schemas.microsoft.com/ado/2009/02/edm/ssdl}Schema").Single(); ssdl.Save(ssdlFile); var storeItemCollection = new StoreItemCollection(new[] { ssdl.CreateReader() }); var csdl = edmx.Descendants("{http://schemas.microsoft.com/ado/2008/09/edm}Schema").Single(); csdl.Save(csdlFile); var edmItemCollection = new EdmItemCollection(new[] { csdl.CreateReader() }); var msl = edmx.Descendants("{http://schemas.microsoft.com/ado/2008/09/mapping/cs}Mapping").Single(); msl.Save(mslFile); var mappingItemCollection = new StorageMappingItemCollection(edmItemCollection, storeItemCollection, new[] { msl.CreateReader() }); return mappingItemCollection; } private static XDocument createEdmx(DbContext contextInstance, string edmxFile, MemoryStream edmxMemoryStream) { var settings = new XmlWriterSettings { Indent = true }; using (var writer = XmlWriter.Create(edmxMemoryStream, settings)) { EdmxWriter.WriteEdmx(contextInstance, writer); } File.WriteAllBytes(edmxFile, edmxMemoryStream.ToArray()); edmxMemoryStream.Position = 0; var edmx = XDocument.Load(edmxMemoryStream); return edmx; } } }
پس از تولید فایل Context.Views.cs یا Context.Views.vb، آنرا به پروژه اضافه کنید.
اینبار نحوه استفاده از آن باید به صورت زیر باشد:
Database.SetInitializer<MyContext>(null);
مرجع:
Entity Framework Code First View Generation Templates On Visual Studio Code Gallery