اشتراکها
با سلام؛ من تازه 2 روزه با Entity Framework آشنا شدم. حالا به روی VS 2012 و از طریق manage nuget pachages و گزینه 6 Entity Framework را نصب کردم و برای قدم اول یک کلاس , یک data layer , و کانکشن استرینگ را هم طبق اون تنظیم کردم. اما در زمان اجرا خطای Could not find schema را برای کانفیگ در کانکشن استرینگ میده. از دوستان کسی میتونه راهنمایی کنه؟ ممنون میشم
Entity Framework half-heartedly supported Domain-Driven Design patterns. But the new-from-scratch EF Core has brought new hope for developers to map your well-designed domain classes to a database, reducing the cases where a separate data model is needed. EF Core 2.1 is very DDD friendly, even supporting things like fully encapsulated collections, backing fields and the return of support for value objects. In this session, we'll review some well-designed aggregates and explore how far EF Core 2.1 goes to act as the mapper between your domain classes and your data store.
نصب: پکیجهای متنوعی از breeze وجود دارند. برای ما بستهی زیر بهترین انتخاب میباشد. با نصب پکیج زیر، breeze در سمت سرور و کلاینت، به همراه ASP.NET Web API 2.2 and Entity Framework 6 نصب میشود:
Install-Package Breeze.WebApi2.EF6
var instance = breeze.config.initializeAdapterInstance("ajax", "angular"); instance.setHttp($http);
Install-Package Breeze.Angular
قلب تپندهی breezejs در کلاینت EntityManager است که نقش data context را در کلاینت، بازی میکند. به برخی از خصوصیات آن میپردازیم:
var manager = new breeze.EntityManager({ dataService: dataService, metadataStore: metadataStore, saveOptions: new breeze.SaveOptions({ allowConcurrentSaves: true, tag: [{}] }) });
var dataService = new breeze.DataService({ serviceName: "/breeze/"+ "Automobile", hasServerMetadata: false, namingConvention: breeze.NamingConvention.camelCase }); var metadataStore = new breeze.MetadataStore({});
- serviceName: نام سرویس دهنده یا کنترلر سمت سرور میباشد. درمورد کنترلر سمت سرور کمی جلوتر بحث میکنیم.
- metadataStore: اطلاعاتی را در مورد تمام آبجکتها (جداول دیتابیس) میدهد. مثل نام فیلدها، نوع فیلدها و...
برای کار با متادیتا دو راه وجود دارد:
1- متا دیتا را خودتان در سمت کلاینت ایجاد نمایید:
var myMetadataStore = new breeze.MetadataStore(); myMetadataStore.addEntityType({...});
var customer = function () { this.City = ""; }; myMetadataStore.registerEntityTypeCtor("Customer", customer);
2- اطلاعات را از سرور دریافت نمایید. در این صورت کنترلر شما باید دارای متد Metadata باشد. بنابراین کنترلی را در سرور به نام Automobile و با محتویات زیر ایجاد نمایید. همانطور که مشاهده میکنید، این کنترلر از ApiController مشتق شده است که تفاوت خاصی با Apiهای دیگر ندارد و تنها به BreezeController مزین شده است. این attribute به NET WebApi کمک میکند که فیلترینگ و مرتب سازی با فرمت oData را فراهم کند و همچنین درک صحیح فرمت json را نیز به کنترلر میدهد.
EFContextProvider: کامپوننتی که تعامل بین کنترلر breeze با Entity Framework را سادهتر میکند و در واقع یک wrapper بر روی دیتاکانتکس یا آبجکت کانتکس میباشد. یکی از وظایف آن ارسال متا دیتا، برای کلاینتهای breeze است.
[BreezeController] public class AutomobileController : ApiController { readonly EFContextProvider<ApplicationDbContext> _contextProvider = new EFContextProvider<ApplicationDbContext>(); [HttpGet] public string Metadata() { return _contextProvider.Metadata(); } [HttpGet] public IQueryable<Customer> Customers() { return _contextProvider.Context.Customers; } [System.Web.Http.HttpPost] public SaveResult SaveChanges(JObject saveBundle) { _contextProvider.BeforeSaveEntitiesDelegate = BeforeSaveEntities; _contextProvider.AfterSaveEntitiesDelegate = afterSaveEntities; return _contextProvider.SaveChanges(saveBundle); } protected Dictionary<Type, List<EntityInfo>> BeforeSaveEntities(Dictionary<Type, List<EntityInfo>> saveMap) { } private void afterSaveEntities(Dictionary<Type, List<EntityInfo>> saveMap, List<KeyMapping> keyMappings) { } }
- saveOptions: نحوهی چگونگی برخورد با ذخیره کردن اطلاعات را مشخص میکند. با ذخیره سازی تغییرات، متد SaveChanges سمت سرور فراخوانی میشود. در breeze میتوان به قبل و بعد از ذخیره سازی اطلاعات دسترسی داشت. یکی از موارد رایج کاربرد آن، اعمال چک کردن دسترسیها، قبل از ذخیره سازی میباشد.
برای ذخیره سازی تغییرات:
manger.saveChanges().then(function success() { }, function failer(e) { });
manger.rejectChanges()
کوئری:بعد از تعریف Entity Manger میتوانیم کوئری خود را اجرا نماییم. کوئری ما شامل گرفتن اطلاعات از جدول Customer، با مرتب سازی بر روی فیلد آیدی میباشد و با اجرا کردن کوئری میتوانیم موفقیت یا عدم موفقیت آنرا بررسی نماییم.
var query = breeze.EntityQuery .from("Customer") .orderBy("Id"); var result= manager.executeQuery(query); result.then(querySucceeded) .fail(queryFailed); query = query.where("Id", "==", 1)
var predicate = new breeze.Predicate("Id", "==", false); query = query.where(predicate) var p1 = new breeze.Predicate("IsArchived", "==", false); var p2 = breeze.Predicate("IsDone", "==", false); var predicate = p1.and(p2); query = query.where(predicate).orderBy("Id")
?$filter=IsArchived eq false&IsDone eq false &$orderby=Id
اعتبارسنجی :اعتبارسنجی در breeze، هم در سمت کلاینت و هم در سمت سرور امکان پذیر میباشد که در مثالی، در قسمت بعدی، validator سفارشی خودمان را خواهیم ساخت و به entity مورد نظر اعمال خواهیم کرد.
breeze دارای یک سری Validator در سطح پراپرتیها است:
- برای انواع اقسام dataType ها مانند Int,string,..
- برای نیازهای رایجی چون: emailAddress,creditCard,maxLength,phone,regularExpression,required,url
هم چنین در breeze امکان تغییر دادن اعتبارسنجیهای پیش فرض نیز وجود دارند. برای مثال برای اینکه در فیلدهای required بتوان متن خالی هم وارد کرد، از دستور زیر میتوان استفاده کرد:
breeze.Validator.required({ allowEmptyStrings: true });
ردیابی تغییرات: هر آیتم Entity دارای EntityAspect است که وضعیت آنرا مشخص میکند و میتواند یکی از وضعیتهای Added،Modified،Deleted،Detached،Unchanged باشد. با مشخص کردن حالت هر آیتم، با فراخوانی SaveChanges تغییرات بر روی دیتابیس اعمال میگردد.
ایجاد آیتم جدید:
manager.createEntity('Customer', jsonValue);
manager.createEntity("Customer", jsonValue, breeze.EntityState.Modified, breeze.MergeStrategy.OverwriteChanges)
manager.createEntity("Customer", item, breeze.EntityState.Deleted)
برای اشنایی بیشتر با امکانات Breeze، قصد داریم یک سایت ایجاد آگهی را راه اندازی کنیم. پیش نیازهای ضروری این بخش typescript ،angularjs ،requirejs هستند. قصد داریم سایتی را برای آگهیهای خرید و فروش خودرو، مشابه با سایت باما ایجاد نماییم:
امکانات این سایت:
- ثبت نام کاربران
- ثبت آگهی توسط کاربران
- ایجاد برچسبهای آگهیها
- امتیاز دهی به آگهیها
- جستجوی آگهیها
- و....
ابتدا نصب پکیجهای زیر
Install-Package angularjs Install-Package angularjs.TypeScript.DefinitelyTyped Install-Package bootstrap Install-Package bootstrap.TypeScript.DefinitelyTyped Install-Package jQuery Install-Package jquery.TypeScript.DefinitelyTyped Install-Package RequireJS Install-Package requirejs.TypeScript.DefinitelyTyped bower install angularAMD
مدلهای برنامه:
ایجاد کلاس BaseEntity
public class BaseEntity { public int Id { get; set; } public bool Status { get; set; } public DateTime CreatedDateTime { get; set; } }
public class Ad : BaseEntity { public string Title { get; set; } public float Price { get; set; } public double Rating { get; set; } public int? RatingNumber { get; set; } public string UserId { get; set; } public DateTime ModifieDateTime { get; set; } public string Description { get; set; } public virtual ICollection<Comment> Comments { get; set; } public virtual IdentityUser User { get; set; } public virtual ICollection<AdLabel> Labels { get; set; } public virtual ICollection<AdMedia> Medias { get; set; } }
ایجاد جدول برچسب
public class Label { public int Id { get; set; } public string Title { get; set; } public int? ParentId { get; set; } public virtual Label Parent { get; set; } public virtual ICollection<Label> Items { get; set; } }
ایجاد جدول مدیا
public class Media { public int Id { get; set; } public string Name { get; set; } public string MimeType { get; set; } }
public class AdLabel { public int Id { get; set; } public virtual Ad Ad { get; set; } public virtual Label Label { get; set; } [Index("IX_AdLabel", 1, IsUnique = true)] public int AdId { get; set; } [Index("IX_AdLabel", 2, IsUnique = true)] public int LabelId { get; set; } public string Value { get; set; } }
public class AdMedia { public int Id { get; set; } public virtual Ad Ad { get; set; } public virtual Media Media { get; set; } [Index("IX_AdMedia", 1, IsUnique = true)] public int AdId { get; set; } [Index("IX_AdMedia", 2, IsUnique = true)] public int MediaId { get; set; } }
public class Comment : BaseEntity { public string Body { get; set; } public double Rating { get; set; } public int? RatingNumber { get; set; } public string EntityName { get; set; } public string UserId { get; set; } public int? ParentId { get; set; } public int? AdId { get; set; } public virtual Comment Parent { get; set; } public virtual Ad Ad { get; set; } public virtual ICollection<Comment> Items { get; set; } public virtual IdentityUser User { get; set; } }
public class Customer:BaseEntity { public string UserId { get; set; } public virtual string DisplayName { get; set; } public virtual string BirthDay { get; set; } public string City { get; set; } public string Address { get; set; } public int? MediaId { get; set; } public bool? NewsLetterSubscription { get; set; } public string PhoneNumber { get; set; } public virtual IdentityUser User { get; set; } public virtual Media Media { get; set; } }
public class Rating { public int Id { get; set; } public string UserId { get; set; } public Double Rate { get; set; } public string EntityName { get; set; } public int DestinationId { get; set; } }
اضافه کردن مدلهای برنامه به ApplicationDbContext
public class ApplicationDbContext : IdentityDbContext<ApplicationUser> { public ApplicationDbContext() : base("DefaultConnection", throwIfV1Schema: false) { } public DbSet<Ad> Ads { get; set; } public DbSet<AdLabel> AdLabels { get; set; } public DbSet<AdMedia> AdMedias { get; set; } public DbSet<Comment> Comments { get; set; } public DbSet<Label> Labels { get; set; } public DbSet<Media> Medias { get; set; } public static ApplicationDbContext Create() { return new ApplicationDbContext(); } }
لود کردن فایل main.js در فایل layout.cshtml ترجیحا در انتهای body
<script src="~/Scripts/require.js" data-main="/app/main"></script>
RequireJS کتابخانهی جاوااسکریپتی برای بارگزاری فایلها در صورت نیاز میباشد. تنها کاری که ما باید انجام بدهیم این است که کدهای خود را داخل moduleها قرار دهیم (در فایلهای جداگانه) و RequireJS در صورت نیاز آنها را load خواهد کرد. همچنین RequireJS وابستگی بین moduleها را نیز مدیریت میکند.
ایجاد فایل main.ts
path: مسیر فایلهای جاوا اسکریپتی
shim: وابستگیهای فایلها(ماژول ها) و export کردن آنها را مشخص میکند.
requirejs.config({ paths: { "app": "app", "angularAmd":"/Scripts/angularAmd", "angular": "/Scripts/angular", "bootstrap": "/Scripts/bootstrap", "angularRoute": "/Scripts/angular-route", "jquery": "/Scripts/jquery-2.2.2", }, waitSeconds: 0, shim: { "angular": { exports: "angular" }, "angularRoute": { deps: ["angular"] }, "bootstrap": { deps: ["jquery"] }, "app": { deps: ["bootstrap","angularRoute"] } } }); require(["app"]);
ایجاد فایل app.ts: کارهایی که در فایل app انجام دادهایم:
ایجاد کنترلر SecurityCtrl و اعمال آن به تگ body
<body ng-controller="SecurityCtrl"> ... </body>
"use strict"; module AdApps { class SecurityCtrl { private $scope: Interfaces.IAdvertismentScope; constructor($scope: Interfaces.IAdvertismentScope) { // security check this.$scope = $scope; } } define(["angularAmd", "angular"], (angularAmd, ng) => { angularAmd = angularAmd.__proto__; var app = ng.module("AngularTypeScript", ['ngRoute']); var viewPath = "app/views/"; var controllerPath = "app/controller/"; app.config(['$routeProvider', $routeProvider => { $routeProvider .when("/", angularAmd.route({ templateUrl: viewPath + "home.html", controllerUrl: controllerPath + "home .js" })) .otherwise({ redirectTo: '/' }); } ]); app.controller('SecurityCtrl', ['$scope', SecurityCtrl]); return angularAmd.bootstrap(app); })}
یکی از مزایای مهم استفاده از Entity framework، خواص راهبری (navigation properties) آن هستند که امکان تهیه کوئریهای بین جداول را به سادگی و به نحوی منطقی فراهم میکنند.
برای مثال دو جدول شهرها و افراد را درنظر بگیرید. مقصود از تعریف جدول شهرها در اینجا، مشخص سازی محل تولد افراد است:
در ادامه این کلاسها را در معرض دید EF Code first قرار داده:
و همچنین تعدادی رکورد آغازین را نیز به جداول مرتبط اضافه میکنیم:
در این حالت برای نمایش لیست نام افراد به همراه محل تولد آنها، بنابر روال سابق SQL نویسی، نوشتن کوئری LINQ زیر بسیار متداول است:
که حاصل آن اجرای کوئری ذیل بر روی بانک اطلاعاتی خواهد بود:
این نوع کوئریهای join دار را به نحو سادهتری نیز میتوان در EF با استفاده از خواص راهبری و بدون join نویسی مستقیم تهیه کرد:
که دقیقا همان خروجی SQL یاد شده را تولید میکند.
مثال دوم:
میخواهیم لیست شهرها را بر اساس تعداد کاربر متناظر به صورت نزولی مرتب کنیم:
همانطور که مشاهده میکنید از خواص راهبری در قسمت order by هم میشود استفاده کرد. خروجی SQL کوئری فوق به صورت زیر است:
مثال سوم:
در ادامه قصد داریم لیست شهرها را به همراه تعداد نفرات متناظر با آنها نمایش دهیم:
در اینجا از خاصیت راهبری People برای شمارش تعداد اعضای متناظر با هر شهر استفاده شده است.
خروجی SQL کوئری فوق به نحو ذیل است:
برای مثال دو جدول شهرها و افراد را درنظر بگیرید. مقصود از تعریف جدول شهرها در اینجا، مشخص سازی محل تولد افراد است:
public class Person { public int Id { get; set; } public string Name { get; set; } [ForeignKey("BornInCityId")] public virtual City BornInCity { get; set; } public int BornInCityId { get; set; } } public class City { public int Id { get; set; } public string Name { get; set; } public virtual ICollection<Person> People { get; set; } }
public class MyContext : DbContext { public DbSet<City> Cities { get; set; } public DbSet<Person> People { get; set; } }
و همچنین تعدادی رکورد آغازین را نیز به جداول مرتبط اضافه میکنیم:
public class Configuration : DbMigrationsConfiguration<MyContext> { public Configuration() { AutomaticMigrationsEnabled = true; AutomaticMigrationDataLossAllowed = true; } protected override void Seed(MyContext context) { var city1 = new City { Name = "city-1" }; var city2 = new City { Name = "city-2" }; context.Cities.Add(city1); context.Cities.Add(city2); var person1 = new Person { Name = "user-1", BornInCity = city1 }; var person2 = new Person { Name = "user-2", BornInCity = city1 }; context.People.Add(person1); context.People.Add(person2); base.Seed(context); } }
public static class Test { public static void RunTests() { Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, Configuration>()); using (var context = new MyContext()) { var peopleAndCitiesList = from person in context.People join city in context.Cities on person.BornInCityId equals city.Id select new { PersonName = person.Name, CityName = city.Name }; foreach (var item in peopleAndCitiesList) { Console.WriteLine("{0}:{1}", item.PersonName, item.CityName); } } } }
SELECT [Extent1].[BornInCityId] AS [BornInCityId], [Extent1].[Name] AS [Name], [Extent2].[Name] AS [Name1] FROM [dbo].[People] AS [Extent1] INNER JOIN [dbo].[Cities] AS [Extent2] ON [Extent1].[BornInCityId] = [Extent2].[Id]
var peopleAndCitiesList = context.People .Select(person => new { PersonName = person.Name, CityName = person.BornInCity.Name });
مثال دوم:
میخواهیم لیست شهرها را بر اساس تعداد کاربر متناظر به صورت نزولی مرتب کنیم:
var citiesList = context.Cities.OrderByDescending(x => x.People.Count()); foreach (var item in citiesList) { Console.WriteLine("{0}", item.Name); }
SELECT [Project1].[Id] AS [Id], [Project1].[Name] AS [Name] FROM ( SELECT [Extent1].[Id] AS [Id], [Extent1].[Name] AS [Name], (SELECT COUNT(1) AS [A1] FROM [dbo].[People] AS [Extent2] WHERE [Extent1].[Id] = [Extent2].[BornInCityId]) AS [C1] FROM [dbo].[Cities] AS [Extent1] ) AS [Project1] ORDER BY [Project1].[C1] DESC
مثال سوم:
در ادامه قصد داریم لیست شهرها را به همراه تعداد نفرات متناظر با آنها نمایش دهیم:
var peopleAndCitiesList = context.Cities .Select(city => new { InUseCount = city.People.Count(), CityName = city.Name }); foreach (var item in peopleAndCitiesList) { Console.WriteLine("{0}:{1}", item.CityName, item.InUseCount); }
خروجی SQL کوئری فوق به نحو ذیل است:
SELECT [Extent1].[Id] AS [Id], (SELECT COUNT(1) AS [A1] FROM [dbo].[People] AS [Extent2] WHERE [Extent1].[Id] = [Extent2].[BornInCityId]) AS [C1], [Extent1].[Name] AS [Name] FROM [dbo].[Cities] AS [Extent1]
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
اشتراکها
مستندات و ویدئوهای EF
اشتراکها