Saat ini saya menggunakan Entity Framework 6 di proyek ASP.NET MVC 5 saya. Setiap klien yang kami miliki memiliki skema database mereka sendiri. Sejauh yang saya temukan sejauh ini tidak mudah untuk mengganti skema saat runtime dengan Entity Framework. Saya telah membuat kelas pembantu yang pada dasarnya mengambil csdl dan file lain dan melakukan pencarian dan penggantian skema tetapi jelas itu menambahkan dampak kinerja yang besar ke aplikasi.

Adakah yang tahu cara mengubah skema saat runtime untuk EF? Jika tidak didukung atau solusi yang mungkin tidak tersedia selain dari apa yang telah saya lakukan, saya harus mengubah alat ORM saya. Apakah ada orang lain yang mendukung ini di luar sana yang juga memungkinkan saya untuk menghasilkan model dari db? Karena membuat semua kelas dengan pemetaan dari awal akan membutuhkan waktu yang sangat lama.

Terima kasih sebelumnya.

0
deved out 12 Oktober 2017, 04:16
1
Tidak yakin tentang mendapatkan skema saat runtime tetapi Anda dapat membuat konteks berdasarkan database yang ada sehingga Anda dapat menambahkan konteks yang berbeda di aplikasi Anda lalu beralih di antara yang ada di runtime. Tetapi biasanya Anda akan membuat pengkodean berdasarkan skema yang ditentukan sehingga Anda mungkin juga membuat kelas bisnis untuk konteks yang berbeda dan hanya mengaktifkan runtime.
 – 
jegtugado
12 Oktober 2017, 04:36

2 jawaban

Dengan asumsi hal-hal berikut ini benar:

  • Anda menggunakan database SQL Server
  • setiap klien Anda menggunakan akun pengguna basis data terpisah

Anda dapat mengatur skema default pengguna di SQL Server.

https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-user-transact-sql

Bagaimana cara mengatur skema default database di SQL Server 2005?

Dan kemudian ubah string koneksi Entity Framework saat run time untuk setiap klien.

Entity Framework mengubah koneksi saat runtime

0
Phyo 12 Oktober 2017, 05:25

Saya baru-baru ini perlu mengatasi masalah ini untuk mengembangkan koneksi multi-penyewa yang andal yang mampu mendukung tidak hanya DB penyewa yang berada di server yang berbeda (yang dapat diselesaikan menggunakan string koneksi) tetapi juga mendukung penyewa-per-skema. Bagian yang sulit di sini adalah pemetaan entitas Anda perlu mencerminkan nama skema untuk menyelesaikan tabel. Ini mengasumsikan bahwa semua penyewa menggunakan skema DB yang sama, hanya nama skema yang berbeda.

Dalam kasus saya, saya menggunakan Mehdi.me DbContextScope yang sebagian mendukung apa yang saya butuhkan karena Anda dapat mengganti dan menyediakan implementasi IDbContextFactory untuk membuat DbContexts Anda menggunakan string koneksi yang sesuai. Bagian kedua saya membuat sedikit ekstensi ke pabrik untuk memastikan bahwa detail skema penyewa dapat melalui inisialisasi konfigurasi entitas.

Jangan ragu untuk melihat apakah itu cocok untuk proyek Anda, atau memberi Anda beberapa ide bagaimana mendapatkan apa yang Anda butuhkan. (https://github.com/StevePy/DbContextScope)

Implementasinya membutuhkan sedikit pengaturan, dan jelas membiasakan diri dengan pola DbContextFactory/DbContextLocator untuk unit kerja tetapi Anda kira-kira memerlukan pengaturan berikut:

  1. Membuat kelas untuk mewakili detail koneksi penyewa yang menerapkan IDbTenant. Kelas ini akan ditautkan ke instance penyewa saat ini adalah mengembalikan string koneksi dan nama skema tempat tabel penyewa akan berada.

  2. Implementasi IDbContextFactory dalam proyek Anda yang akan membuat instance DbContext. Pabrik ini biasanya menerima konstruktor default, string koneksi, dan sekarang instance dari IDbTenant yang dibuat adalah langkah 1.

  3. Inisialisasi IoC Anda jika ada untuk menginisialisasi DbContextScopeFactory dengan IDbContextFactory yang dibuat pada langkah 2. Ini akan terlihat seperti:

ioc.Register<IDbContextScopeFactory>( ()=> {new DbContextScopeFactory(new SqlServerTenantDbContextFactory());});

Dimana SqlServerTenantDbContextFactory adalah implementasi yang dibuat pada langkah 2. Di atas adalah kira-kira proses pendaftaran untuk Autofac IoC. Pada dasarnya Anda hanya ingin memastikan ketika DbContextScopeFactory dipakai, Anda memberikan DbContextFactory Anda.

Sebuah implementasi dari ContextFactory.

public class SqlServerTenantDbContextFactory : IDbContextFactory
{
   TDbContext IDbContextFactory.CreateDbContext<TDbContext>()
   {
      return (TDbContext)Activator.CreateInstance<TDbContext>();
   }

   TDbContext IDbContextFactory.CreateDbContext<TDbContext>(IDbTenant tenant)
   {
      var connection = DbProviderFactories.GetFactory("System.Data.SqlClient").CreateConnection();
      // based on the provider set up in <providers> configration under <entityFramework>...
      connnection.ConnectionString = tenant?.ConnectionString;
      return (TDbContext)Activator.CreateInstance(typeof(TDbContext), tenant, connection, true);
   }


   TDbContext IDbContextFactory.CreateDbContext<TDbContext>(string connectionString)
   {
      var connection = DbProviderFactories.GetFactory("System.Data.SqlClient").CreateConnection();
      connnection.ConnectionString = connectionString;
      return (TDbContext)Activator.CreateInstance(typeof(TDbContext), connection, true);
   }
}

Perubahan konfigurasi terakhir adalah EntityTypeConfiguration menambahkan konstruktor yang menerima IDbTenant dan menambahkan atribut [ImportingConstructor] ke konstruktor tersebut. ContextFactory akan mengurus sisanya. Jadi misalnya, diberikan entitas yang disebut "Pesanan", Anda akan menentukan konfigurasi tipe entitas seperti:

public class OrderConfiguration : EntityTypeConfiguration<Order>
{
   [ImportingConstructor]
   public OrderConfiguration(IDbTenant tenant)
      : base()
   {
       ToTable("Orders", tenant.SchemaName);
       // HasKey(...);
       // HasMany(...);
       // etc. etc. etc.
   }
}

Tidak yakin apakah ini dapat diadaptasi untuk melayani implementasi kode-pertama, tetapi saya meragukannya karena pola itu ingin bertanggung jawab atas definisi skema db dan migrasi yang akan berantakan ketika harus beralih di antara skema atau server.

Mungkin banyak hal yang perlu diperhatikan, terutama jika Anda belum pernah memiliki pengalaman sebelumnya dengan Mehdi.me DbContextScope, tapi mudah-mudahan ini bisa memberi Anda beberapa ide.

Setelah ini disetel, satu-satunya perubahan dari pola Mehdi.me normal adalah ketika Anda mengambil konteks menggunakan DbContextLocator, berikan instance IDbTenant:

private MyAppContext Context
{
  get { return ContextLocator.Get<MyAppContext>(_tenant); }
}

Di mana _tenant diinisialisasi berdasarkan penyewa Anda yang masuk. (Yaitu, strategi identifikasi penyewa yang menarik detail dari OWIN auth, atau status sesi...) Dari sini, pabrik konteks mengambil alih dan akan menginisialisasi konteks Anda menggunakan detail penyewa.

0
Steve Py 12 Oktober 2017, 13:17