شروع به کار با EF Core 1.0 - قسمت 3 - انتقال مهاجرت‌ها به یک اسمبلی دیگر
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: چهار دقیقه

در قسمت قبل، تغییرات Migrations، در EF Core 1.0 بررسی و گردش کاری آن به همراه مثال‌هایی ارائه شدند. در این قسمت یک سری از نکات تکمیلی EF Core Migrations را بررسی خواهیم کرد.


انتقال Context و Migrations به یک اسمبلی دیگر

تا اینجا اگر مثال بررسی شده را دنبال کرده باشید، دو پوشه‌ی Entities و Migrations را به همراه فایل‌‌های موجودیت‌ها، Context برنامه و Migrations آن‌ها، در همان پروژه‌ی اصلی برنامه، خواهید داشت:


در ادامه قصد داریم بانک اطلاعاتی آزمایشی برنامه را drop کرده، پوشه‌ی Migrations را حذف و صرفا دو فایل ApplicationDbContextSeedData و DBInitialization آن‌را نگه داریم.
کلاس Person را به اسمبلی جدید Entities و کلاس ApplicationDbContext را به اسمبلی جدید DataLayer منتقل می‌کنیم:


اسمبلی جدید Core1RtmEmptyTest.Entities از نوع NET Core Class Library. است و صرفا حاوی کلاس‌های موجودیت‌های برنامه‌است.
اسمبلی جدید Core1RtmEmptyTest.DataLayer نیز از نوع NET Core Class Library. بوده و حاوی تعاریف Context برنامه، به همراه Migrations و تنظیمات آن خواهد بود.

تا اینجا با این نقل و انتقالات، نیاز است وابستگی‌های DataLayer را اصلاح کنیم. بنابراین فایل project.json آن‌را گشوده و به نحو ذیل تکمیل نمائید:
{
  "version": "1.0.0-*",

    "dependencies": {
        "Core1RtmEmptyTest.Entities": "1.0.0-*",
        "Microsoft.EntityFrameworkCore": "1.0.0",
        "Microsoft.EntityFrameworkCore.SqlServer": "1.0.0",
        "Microsoft.Extensions.Configuration.Abstractions": "1.0.0",
        "NETStandard.Library": "1.6.0"
    },

  "frameworks": {
    "netstandard1.6": {
      "imports": "dnxcore50"
    }
  }
}
به این صورت ارجاعی به اسمبلی Core1RtmEmptyTest.Entities به پروژه اضافه شده‌است (تا کلاس Person در ApplicationDbContext شناسایی شود) به همراه وابستگی‌های EF و SQL Server که مورد نیاز Context برنامه هستند.
وابستگی Microsoft.Extensions.Configuration.Abstractions برای کار با IConfigurationRoot اضافه شده‌است (دسترسی به تنظیمات برنامه از طریق تزریق وابستگی‌ها).

به علاوه اکنون به پروژه‌ی وب اصلی مراجعه کرده و فایل project.json آن‌را جهت افزودن ارجاعاتی به این دو اسمبلی جدید، ویرایش کنید:
{
    "dependencies": {
        // same as before
        "Core1RtmEmptyTest.Entities": "1.0.0-*",
        "Core1RtmEmptyTest.DataLayer": "1.0.0-*"
    }
}
به این ترتیب Startup برنامه می‌تواند محل جدید کلاس ApplicationDbContext را شناسایی کند و برنامه کامپایل شود.


فعال سازی Migrations و قرار دادن فایل‌های آن در اسمبلی Core1RtmEmptyTest.DataLayer

در ادامه اگر مانند قسمت قبل بخواهیم مهاجرت‌ها را اضافه کنیم، به خطای ذیل خواهیم رسید:
D:\Prog\1395\Core1RtmEmptyTest\src\Core1RtmEmptyTest>dotnet ef migrations add InitialDatabase
Your target project 'Core1RtmEmptyTest' doesn't match your migrations assembly 'Core1RtmEmptyTest.DataLayer'.
Either change your target project or change your migrations assembly.
برای حل این مشکل، بجای اینکه دستور فوق را از مسیر src\Core1RtmEmptyTest صادر کنیم که همان ریشه‌ی اصلی پروژه‌ی وب است، اینبار باید دستور را از ریشه‌ی پروژه DataLayer صادر کنیم. اما اگر چنین کاری را انجام دهیم، پیام یافتن نشدن فایل اجرایی ابزارهای خط فرمان EF را دریافت می‌کنیم:
D:\Prog\1395\Core1RtmEmptyTest\src\Core1RtmEmptyTest.DataLayer>dotnet ef migrations add InitialDatabase
No executable found matching command "dotnet-ef"
علت اینجا است که باید مجددا فایل Core1RtmEmptyTest.DataLayer\project.json را گشوده و این ابزارها را در آن فعال کنیم:
{
     // same as before

    "tools": {
        "Microsoft.EntityFrameworkCore.Tools": {
            "version": "1.0.0-preview2-final",
            "imports": [
                "portable-net45+win8"
            ]
        }
    },

     // same as before
}
پس از فعال سازی ابزارهای EF در پروژه‌ی DataLayer، اکنون باز هم موفق به اجرای دستور فوق نخواهیم شد:
D:\Prog\1395\Core1RtmEmptyTest\src\Core1RtmEmptyTest.DataLayer>dotnet ef migrations add InitialDatabase
Could not invoke this command on the startup project 'Core1RtmEmptyTest.DataLayer'.
This preview of Entity Framework tools does not support commands on class library projects in ASP.NET Core and .NET Core applications.
عنوان می‌کند که پروژه‌ی startup را نمی‌تواند پیدا کند، برای حل این مشکل، دستور را به نحو ذیل ویرایش کنید:
 D:\Prog\1395\Core1RtmEmptyTest\src\Core1RtmEmptyTest.DataLayer>dotnet ef --startup-project ../Core1RtmEmptyTest/ migrations add InitialDatabase
Done. To undo this action, use 'dotnet ef migrations remove'
در اینجا با ذکر صریح startup-project، عملیات تولید فایل‌های Migrations با موفقیت انجام شدند:



اعمال کلاس‌های Migrations تولید شده به بانک اطلاعاتی

پس از تولید موفقیت آمیز فایل‌های مهاجرت، برای اعمال آن‌ها به بانک اطلاعاتی، اینبار نیز دستور را از همان پوشه‌ی DataLayer با پارامتر پروژه‌ی آغازین اجرا می‌کنیم:
D:\Prog\1395\Core1RtmEmptyTest\src\Core1RtmEmptyTest.DataLayer>dotnet ef --startup-project ../Core1RtmEmptyTest/ database update
Applying migration '13950527070105_InitialDatabase'.
Done.
در اینجا نیز ذکر پارامتر startup-project جهت اجرای موفقیت آمیز دستور الزامی است.


بنابراین به صورت خلاصه

- ابتدا قسمت tools تنظیمات پروژه‌ی data layer را برای فعال سازی دستورات خط فرمان EF ویرایش کنید.
- سپس از طریق خط فرمان به پوشه‌ی data layer وارد شوید. اینبار باید دستورات EF را از ریشه‌ی این پوشه، بجای پوشه‌ی اصلی برنامه صادر کرد.
- در اینجا دستورات افزودن مهاجرت‌ها و به روز رسانی بانک اطلاعاتی، همانند قبل هستند. فقط ذکر محل واقع شدن پوشه‌ی آغازین برنامه توسط پارامتر startup-project الزامی است.
  • #
    ‫۷ سال و ۱۲ ماه قبل، یکشنبه ۴ مهر ۱۳۹۵، ساعت ۱۴:۱۶
    اگر علاقمند بودید تا کار افزودن مهاجرت‌ها، به همراه تولید خودکار نام فایل، بر اساس تاریخ و ساعت روز باشد، می‌توان از دستورات ذیل در خط فرمان استفاده کرد (و یا درست کردن یک فایل bat. برای آن):
    For /f "tokens=2-4 delims=/ " %%a in ('date /t') do (set mydate=%%c_%%a_%%b)
    For /f "tokens=1-2 delims=/:" %%a in ("%TIME: =0%") do (set mytime=%%a%%b)
    dotnet ef --configuration Release --startup-project ../ProjName/ migrations add V%mydate%_%mytime%
  • #
    ‫۷ سال و ۱۰ ماه قبل، یکشنبه ۳۰ آبان ۱۳۹۵، ساعت ۱۸:۴۲
    به روز رسانی EF Core 1.1
    پروژه DataLayer برای اجرای فرامین Migrations باید دارای این وابستگی‌ها باشد:
    PM> Install-Package Microsoft.EntityFrameworkCore.SqlServer
    PM> Install-Package Microsoft.EntityFrameworkCore.Tools.DotNet –Pre
    PM> Install-Package Microsoft.EntityFrameworkCore.Design
    PM> Install-Package Microsoft.EntityFrameworkCore.SqlServer.Design
    و یا به صورت خلاصه:
    {
        "version": "1.0.0-*",
    
        "dependencies": {
            "Core1RtmEmptyTest.Entities": "1.0.0-*",
            "Microsoft.EntityFrameworkCore": "1.1.0",
            "Microsoft.EntityFrameworkCore.Design": "1.1.0",
            "Microsoft.EntityFrameworkCore.SqlServer": "1.1.0",
            "Microsoft.EntityFrameworkCore.SqlServer.Design": "1.1.0",
            "Microsoft.Extensions.Configuration.Abstractions": "1.1.0",
            "NETStandard.Library": "1.6.1"
        },
    
        "tools": {
            "Microsoft.EntityFrameworkCore.Tools.DotNet": {
                "version": "1.1.0-preview4-final",
                "imports": [
                    "portable-net45+win8"
                ]
            }
        },
    
        "frameworks": {
            "netstandard1.6": {
                "imports": "dnxcore50"
            }
        }
    }
    • #
      ‫۷ سال و ۱۰ ماه قبل، یکشنبه ۳۰ آبان ۱۳۹۵، ساعت ۲۳:۴۵
      فایل project.json که بنده تنظیم کردم در DataLayer :

      {
        "version": "1.0.0-*",
        "dependencies": {
          //.. other assemblies
          "CacheManager.Serialization.Json": "0.9.1",
          "EFSecondLevelCache.Core": "1.0.1",
          "Microsoft.AspNetCore.Diagnostics": "1.1.0",
          "Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore": "1.1.0",
          "Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.1.0",
          "Microsoft.EntityFrameworkCore.InMemory": "1.1.0",
          "Microsoft.Extensions.Configuration.Binder": "1.1.0",
          "Microsoft.Extensions.Options": "1.1.0",
          "System.Linq": "4.3.0",
          "System.Reflection": "4.3.0",
          "Microsoft.EntityFrameworkCore": "1.1.0",
          "Microsoft.EntityFrameworkCore.Design": "1.1.0",
          "Microsoft.EntityFrameworkCore.SqlServer": "1.1.0",
          "Microsoft.EntityFrameworkCore.SqlServer.Design": "1.1.0",
          "Microsoft.Extensions.Configuration.Abstractions": "1.1.0",
          "NETStandard.Library": "1.6.1"
        },
        "tools": {
          "Microsoft.EntityFrameworkCore.Tools.DotNet": {
            "version": "1.2.0-preview4-22736",
            "imports": [
              "portable-net45+win8"
            ]
          }
      
        },
        "frameworks": {
          "netcoreapp1.1": {
            "dependencies": {
              "Microsoft.NETCore.App": {
                "type": "platform",
                "version": "1.1.0"
              }
            },
            "imports": [
              "dnxcore50",
              "portable-net45+win8"
            ]
          }
        }
      }

        و نتیجه اینکه عدم شناسایی command‌های Migrations : (حتی بعد از بروزرسانی بسته‌ها - یکبار اقدام به بستن و باز کردن مجدد Solution انجام شد اما تاثیری نداشت)

      مشکل در خط فرمان PMC (package Manager console) رفع نشده است اما با اجرای CMD.exe در مسیر پروژه DataLayer و با استفاده از دستور زیر عملیات Migrations به درستی عمل میکند : (اطلاعات بیشتر )

      dotnet ef --startup-project ../Core1RtmEmptyTest/ migrations add InitialDatabase  

      • #
        ‫۷ سال و ۱۰ ماه قبل، دوشنبه ۱ آذر ۱۳۹۵، ساعت ۰۱:۴۳
        - من چون از PowerShell برای اینکار استفاده نمی‌کنم، پیشنیازهای خط فرمان dotnet ef را نوشتم که امتحان شده و بدون مشکل کار می‌کند (و تغییر یا بسته‌ی دیگری را هم نیاز ندارد).
        - دستورات PowerShell دیگر شامل enable-migration نیست و اینبار add-migration است.
        برای فعالسازی آن‌ها هم نیاز است از همان بسته‌ی Microsoft.EntityFrameworkCore.Tools استفاده شود (که برای EF 1.1 هم به روز شده‌است):
        "dependencies": {
               "Microsoft.EntityFrameworkCore.Tools": {
                "version": "1.1.0-preview4-final",
                "imports": [
                    "portable-net45+win8"
                ],
                "type": "build"
           },
                // the rest ...
        },
            "tools": {
                "Microsoft.EntityFrameworkCore.Tools": {
                    "version": "1.1.0-preview4-final",
                    "imports": [
                        "portable-net45+win8"
                    ]
                },
                // the rest ...
        }
        تنها این بسته‌است که شامل فایل‌های ps1 مربوط به PowerShell است (واقع در مسیر زیر):
        %UserProfile%\.nuget\packages\Microsoft.EntityFrameworkCore.Tools\1.1.0-preview4-final\tools
        و این بسته جهت بارگذاری فایل‌های PowerShell توسط نیوگت، حتما باید در قسمت dependencies ذکر شود (علاوه بر قسمت tools).
        ذکر آن در قسمت dependencies سبب می‌شود که قسمت frameworks نیز به نحو ذیل تغییر کند (و پس از این تغییرات نیاز است یکبار ویژوال استودیو را بسته و مجددا باز کنید):
        "frameworks": { 
                "netcoreapp1.1": {
                    "dependencies": {
                        "Microsoft.NETCore.App": {
                            "type": "platform",
                            "version": "1.1.0"
                        }
                    },
                    "imports": [
                        "dnxcore50",
                        "portable-net45+win8"
                    ]
                }
            }
  • #
    ‫۷ سال و ۶ ماه قبل، یکشنبه ۲۹ اسفند ۱۳۹۵، ساعت ۱۵:۴۸
    یک نکته‌ی تکمیلی
    اگر پس از مهاجرت به VS 2017، خطای ذیل را در حین اجرای مهاجرت‌ها مشاهده کردید:
    error MSB4006: There is a circular dependency in the target dependency graph involving target "GetEFProjectMetadata"
    الف) اسمبلی‌های ختم به Design و Tools باید دارای ویژگی "PrivateAssets="All شوند (میدان دید محدود به اسمبلی جاری) تا مشکلات circular dependency را ایجاد نکنند. یک نمونه 
    ب) اگر در دستورات شما «configuration Release--» وجود دارد، آن‌را حذف کنید و نیازی به آن نیست؛ چون به صورت خودکار توسط MSBuild مدیریت می‌شود.

    نمونه‌ای از تغییرات مورد نیاز جهت رفع این مشکل
  • #
    ‫۷ سال و ۳ ماه قبل، دوشنبه ۱۵ خرداد ۱۳۹۶، ساعت ۱۷:۲۵
    جهت ایجاد رفرنس در محیط VsCode توسط Cli ابتدا یک پروژه به عنوان مثال یک class Library ایجاد کرده:
    dotnet new classlib c1
    و سپس آن را توسط کامند زیر رفرنس میدهیم:
    dotnet add reference ../c1/c1.csproj
     و در فایل Proj پروژه اصلی چنین مدخلی اضافه خواهد شد؛ سپس vscode از شما خواهد خواست که بسته‌های خود را به روز کنید:
    <ItemGroup>
        <ProjectReference Include="..\c1\c1.csproj" />
      </ItemGroup>

     
    • #
      ‫۷ سال و ۳ ماه قبل، دوشنبه ۱۵ خرداد ۱۳۹۶، ساعت ۱۷:۴۶
      نکته تکمیلی‌تر جهت ایجاد sln در این حالت استفاده از دستور زیر برای ساخت یک solution جدید با نام پوشه والد است:
      dotnet new sln
      سپس برای هر یکی از فایل‌های پروژه یک دایرکتوری ایجاد کرده و پروژه مربوط به هر کدام را داخل آن ایجاد میکنیم.

       سپس از طریق دستور زیر آن‌ها را در sln ثبت می‌نماییم: 
      >dotnet sln add mymvc/mymvc.csproj
      Project `mymvc\mymvc.csproj` added to the solution.
      >dotnet sln add models/models.csproj
      Project `models\models.csproj` added to the solution.
  • #
    ‫۷ سال و ۱ ماه قبل، جمعه ۲۷ مرداد ۱۳۹۶، ساعت ۲۳:۳۳
    روش ارتقاء به EF Core 2.0

    حداقل وابستگی‌های مورد نیاز جهت کار با EF Core 2.0 و همچنین اجرای مهاجرت‌های آن به صورت ذیل است:
      <ItemGroup>
        <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.0" />
        <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.0" PrivateAssets="All" />
        <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.0" PrivateAssets="All" />
        <PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="2.0.0" />
        <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.0.0" />
      </ItemGroup>
      <ItemGroup>
        <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
      </ItemGroup>

    سپس تغییر مهم دیگر، ندید گرفتن پارامتر startup-project به طور کامل است (نکته‌ای که در مطلب فوق در مورد آن بحث شده‌است). اگر Context برنامه‌ی شما دارای پارامتر است، EF Core 2.0 «در حین اجرای مهاجرت‌ها» به صورت صریح نیاز دارد بداند که چطور باید این Context را وهله سازی کرد و دیگر مانند قبل سعی نمی‌کند وابستگی‌های تزریق شده‌ی در آن‌را حدس بزند:
    Unable to create an object of type 'ApplicationDbContext'. 
    Add an implementation of 'IDesignTimeDbContextFactory<ApplicationDbContext>' to the project, 
    or see https://go.microsoft.com/fwlink/?linkid=851728 for additional patterns supported at design time.
    به همین جهت در اینجا باید اینترفیس جدید IDesignTimeDbContextFactory را پیاده سازی کرده و سپس مشخص کنید چگونه می‌توان یک ApplicationDbContext را وهله سازی کرد:
        public class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
        {
            public ApplicationDbContext CreateDbContext(string[] args)
            {
                return new ApplicationDbContext(siteSettings, httpContextAccessor, hostingEnvironment, logger);
            }
        }
    این کلاس ویژه باید در اسمبلی قرار گیرد که Context برنامه در آن تعریف شده‌است و یافتن آن توسط EF Core 2.0 خودکار است.
    یک نمونه پیاده سازی کامل آن را که در پروژه‌ی DNTIdentity بکار رفته‌است، در اینجا می‌توانید مشاهده کنید.

    مثالی دیگر برای حالتیکه سازنده‌ی کلاس Context یک <DbContextOptions<T را دریافت می‌کند:
    public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<MyDbContext> 
    { 
        public MyDbContext CreateDbContext(string[] args) 
        { 
            IConfigurationRoot configuration = new ConfigurationBuilder() 
                .SetBasePath(Directory.GetCurrentDirectory()) 
                .AddJsonFile("appsettings.json") 
                .Build(); 
            var builder = new DbContextOptionsBuilder<MyDbContext>(); 
            var connectionString = configuration.GetConnectionString("DefaultConnection"); 
            builder.UseSqlServer(connectionString); 
            return new MyDbContext(builder.Options); 
        } 
    }
    • #
      ‫۷ سال و ۱ ماه قبل، شنبه ۲۸ مرداد ۱۳۹۶، ساعت ۲۱:۱۶
      بعد از ارتقاء به EF Core 2.0 دستورات dotnet tools هم زمان بیشتری نسبت به قبل برای اجرا شدن می‌گیره و هم باعث فریز شدن ویژوال استدیو ۲۰۱۷ می‌شه، این مشکل بعد از ارتقاء برای شما هم پیش اومد؟
      • #
        ‫۷ سال و ۱ ماه قبل، شنبه ۲۸ مرداد ۱۳۹۶، ساعت ۲۲:۱۲
        من مدتی هست که از نگارش کامل ویژوال استودیو دیگر استفاده نمی‌کنم. با VSCode هیچ مشکلی نیست و همه چیز روان است. نگارش کامل ویژوال استودیو مربوط به زمانی بود که یک فایل ISO چندگیگابایتی را ارائه می‌دادند و تا سه سال بعدش نیازی به به‌روز رسانی نبود. سیستم کار NET Core. چابک هست و با VSCode بیشتر سازگاری دارد تا ویژوال استودیوی سنگین و حجیم.
        • #
          ‫۶ سال و ۹ ماه قبل، چهارشنبه ۸ آذر ۱۳۹۶، ساعت ۱۷:۳۰
          در VS Code برای ویوها و  Razor  و در کل Intellisense از چه چیزی استفاده میکنید؟
      • #
        ‫۷ سال و ۱ ماه قبل، یکشنبه ۲۹ مرداد ۱۳۹۶، ساعت ۰۱:۵۹
        سلام
        آپدیت 15.3.1 رو که امروز ریلیز شده نصب کنید.یکسری از موارد رفع شده و برخی هم نه.
    • #
      ‫۵ سال و ۱ ماه قبل، شنبه ۱۲ مرداد ۱۳۹۸، ساعت ۰۵:۱۷
      در این بخش از مطلب که گفته بودید : " ندید گرفتن پارامتر startup-project به طور کامل است " بدین معنی هست که در هنگام اجرای فرمان migration دیگر نیازی نیست که پروژه استارت آپ رو قید کنیم ؟ (لطفا این بخش رو کمی توضیح دهید)
      • #
        ‫۵ سال و ۱ ماه قبل، شنبه ۱۲ مرداد ۱۳۹۸، ساعت ۱۱:۴۲
        «... ندید گرفتن پارامتر startup-project به طور کامل است (نکته‌ای که در مطلب فوق در مورد آن بحث شده‌است). اگر Context برنامه‌ی شما دارای پارامتر است، EF Core 2.0 «در حین اجرای مهاجرت‌ها» به صورت صریح نیاز دارد بداند که چطور باید این Context را وهله سازی کرد و دیگر مانند قبل سعی نمی‌کند وابستگی‌های تزریق شده‌ی در آن‌را حدس بزند: ...»
        =
        ندید گرفتن پارامتر startup-project جهت حدس زدن نحوه تامین وابستگی‌های تزریق شده
  • #
    ‫۶ سال و ۷ ماه قبل، پنجشنبه ۱۹ بهمن ۱۳۹۶، ساعت ۱۴:۰۹
    سلام؛ من بعد از انتقال کانتکس و کلاس‌های مدل به اسمبلی‌های خودشون اقدام به اضافه کردن مهاجرت‌ها کردم ولی با خطای  زیر مواجه شدم :
    Unable to create an object of type 'ApplicationDbContext'. Add an implementation of 'IDesignTimeDbContextFactory<ApplicationDbContext>' to the project, or see https://go.microsoft.com/fwlink/?linkid=851728 for additional patterns supported at design time.
     ضمنا سازنده کانتکست:
     public ApplicationDbContext(DbContextOptions options) : base(options)
            {
                
            }
    دستور اضافه کردن مهاجرت‌ها:
    dotnet ef --startup-project ../MohasebKhodro/ migrations add InitialDatabase
  • #
    ‫۱ سال قبل، چهارشنبه ۱۱ مرداد ۱۴۰۲، ساعت ۲۲:۰۳
    ایجاد نام جداول به صورت جمع (Pluralized) و داینامیک :
    اگه از روش خودکار کردن تعاریف DbSet ها استفاده کرده باشیم چون دیگر در داخل کلاس Context برنامه، Dbset تعریف نمی‌شود معمولا برای نام گذاری جداول که به صورت جمع باشند از اتریبیوت Table استفاده می‌کنیم.
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    
    [Table("Users")]
    public class User : BaseEntity
    {
        public long Id { get; set; }
    
        [Required]
        public string FullName { get; set; } = null!;
    }
    برای اینکه نام جداول به صورت خودکار به صورت جمع ایجاد شوند میتوان از این متد استفاده کرد:
    using Microsoft.EntityFrameworkCore;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Reflection;
    
    namespace ProjectName.Common.EfHelpers;
    
    public static class EfToolkit
    {
        /// <summary>
        /// ایجاد نام موجودیت‌ها
        /// نام موجودیت اگر اتریبیوت تیبل داشته باشد
        /// از همان نام استفاده میشود و اگر نداشته باشد
        /// نامش جمع بسته میشود
        /// </summary>
        /// <param name="builder"></param>
        public static void MakeTableNamesPluralized(this ModelBuilder builder)
        {
            var entityTypes = builder.Model.GetEntityTypes();
    
            foreach (var entityType in entityTypes)
            {
                // Get the CLR type of the entity
                var entityClrType = entityType.ClrType;
                var hasTableAttribute = entityClrType.GetCustomAttribute<TableAttribute>();
    
                // Apply the pluralized table name for the entity
                if (hasTableAttribute is null)
                {
                    // Get the pluralized table name
                    var pluralizedTableName = GetPluralizedTableName(entityClrType);
                    builder.Entity(entityClrType).ToTable(pluralizedTableName);
                }
            }
        }
    
        /// <summary>
        /// گرفتن نام تایپ و عوض کردن نام آن از مفرد به جمع
        /// Singular to plural
        /// Category => Categories
        /// Box => Boxes
        /// Bus => Buses
        /// Computer => Computers
        /// </summary>
        /// <param name="entityClrType"></param>
        /// <returns></returns>
        private static string GetPluralizedTableName(Type entityClrType)
        {
            // Example implementation (Note: This is a simple pluralization logic and might not cover all cases)
            var typeName = entityClrType.Name;
            if (typeName.EndsWith("y"))
            {
                // Substring(0, typeName.Length - 1)
                // Range indexer
                var typeNameWithoutY = typeName[..^1];
                return typeNameWithoutY + "ies";
            }
    
            if (typeName.EndsWith("s") || typeName.EndsWith("x"))
            {
                return typeName + "es";
            }
            return typeName + "s";
        }
    }
    
    نحوه فراخوانی در متد OnModelCreating:
    protected override void OnModelCreating(ModelBuilder builder)
    {
        // it should be placed here, otherwise it will rewrite the following settings!
        base.OnModelCreating(builder);
        builder.RegisterAllEntities(typeof(BaseEntity));
        builder.MakeTableNamesPluralized();
        builder.ApplyConfigurationsFromAssembly(typeof(ApplicationDbContext).Assembly);
    }
    هر موجودیتی که اتریبیوت Table داشته باشد از همان نام برای جدول استفاده می‌شود در غیر اینصورت نام انتیتی به صورت جمع ایجاد می‌گردد.
    قبل از اینکه نام جداول نیز جمع بسته شود تمامی موجودیت‌ها به صورت خودکار اضافه می‌شوند.
    public static class EfToolkit
    {
        /// <summary>
        /// ثبت تمامی انتیتی‌ها
        /// <param name="builder"></param>
        /// <param name="type"></param>
        /// </summary>
        public static void RegisterAllEntities(this ModelBuilder builder, Type type)
        {
            var entities = type.Assembly.GetTypes()
                .Where(x => x.BaseType == type);
            foreach (var entity in entities)
                builder.Entity(entity);
        }
    }  
    هر کلاسی در لایه موجودیت‌ها از BaseEntity ارث بری کرده باشد به عنوان یک Entity شناخته می‌شود.
    • #
      ‫۱ سال قبل، پنجشنبه ۱۲ مرداد ۱۴۰۲، ساعت ۱۴:۱۵
      کتابخانه استاندارد تبدیل اسامی، به جمع آن‌ها در دات نت، کتابخانه‌ی معروف Humanizer است. بهتر است برای این نوع کارها از آن استفاده کنید چون تهیه‌ی حالت جمع اسامی، استثناء زیاد دارد.