2016-09-06 23 views
8

tôi cố gắng triển khai Thực thể khung thành dự án của tôi! Dự án của tôi là dựa trên plugin vì vậy tôi không biết đối tượng nào tôi phải lưu vào cơ sở dữ liệu.Cập nhật tự động khung thực thể

Tôi đã thực hiện nó như vậy:

public class DatabaseContext : DbContext 
{ 
    public DatabaseContext() : base() 
    { 
     Database.Initialize(true); 
    } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     foreach(PluginDto plugin in BackendContext.Current.PluginManager._plugins) { 
      foreach(Type obj in plugin.plugin.getPluginDatabaseObjects()) 
      { 
       Type typ = typeof(EntityTypeConfiguration<>).MakeGenericType(obj); 

       List<MethodInfo> l = modelBuilder.GetType().GetMethods().ToList<MethodInfo>(); 

       MethodInfo m_Entitiy = modelBuilder.GetType().GetMethod("Entity").MakeGenericMethod(new Type[] { obj }); 
       var configObj = m_Entitiy.Invoke(modelBuilder, null); 

       MethodInfo m_ToTable = configObj.GetType().GetMethod("ToTable", new Type[] { typeof(String) }); 
       m_ToTable.Invoke(configObj, new object [] { obj.Name }); 
      } 
     } 

     base.OnModelCreating(modelBuilder); 
    } 

} 

Nhưng tôi nhận được ngoại lệ này, khi tôi đưa ra một sự thay đổi:

The model backing the 'DatabaseContext' context has changed since the database was created. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=238269).

Lỗi này là hoàn toàn logic. Cơ sở dữ liệu không đồng bộ, nhưng làm thế nào tôi sẽ nhận được bản cập nhật? Tôi đã đọc điều gì đó về điều này:

var config = new DbMigrationsConfiguration<MyContext> { AutomaticMigrationsEnabled = true }; 
var migrator = new DbMigrator(config); 
migrator.Update(); 

Nhưng tôi không biết cách sử dụng và cách sử dụng đúng cách! Cảm ơn bạn rất nhiều!

EDIT1: Khi tôi cố gắng để: Enable-Migrations -EnableAutomaticMigrations

Tôi đã nhận lỗi này:

System.NullReferenceException: Object reference not set to an instance of an object. 
    at SOM.Backend.database.DatabaseContext.OnModelCreating(DbModelBuilder modelBuilder) in C:\Users\Flo\Documents\Visual Studio 2015\Projects\SOM\Backend\BackendService\BackendService\database\DatabaseContext.cs:line 26 
    at System.Data.Entity.Internal.LazyInternalContext.CreateModelBuilder() 
    at System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext) 
    at System.Data.Entity.Internal.RetryLazy`2.GetValue(TInput input) 
    at System.Data.Entity.Internal.LazyInternalContext.InitializeContext() 
    at System.Data.Entity.Internal.LazyInternalContext.MarkDatabaseInitialized() 
    at System.Data.Entity.Database.Initialize(Boolean force) 
    at SOM.Backend.database.DatabaseContext..ctor() in C:\Users\Flo\Documents\Visual Studio 2015\Projects\SOM\Backend\BackendService\BackendService\database\DatabaseContext.cs:line 21 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 
    at System.Data.Entity.Infrastructure.DbContextInfo.CreateInstance() 
    at System.Data.Entity.Infrastructure.DbContextInfo..ctor(Type contextType, DbProviderInfo modelProviderInfo, AppConfig config, DbConnectionInfo connectionInfo, Func`1 resolver) 
    at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration, DbContext usersContext, DatabaseExistenceState existenceState, Boolean calledByCreateDatabase) 
    at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration) 
    at System.Data.Entity.Migrations.Design.MigrationScaffolder..ctor(DbMigrationsConfiguration migrationsConfiguration) 
    at System.Data.Entity.Migrations.Design.ToolingFacade.ScaffoldRunner.Run() 
    at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate) 
    at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate) 
    at System.Data.Entity.Migrations.Design.ToolingFacade.Run(BaseRunner runner) 
    at System.Data.Entity.Migrations.Design.ToolingFacade.ScaffoldInitialCreate(String language, String rootNamespace) 
    at System.Data.Entity.Migrations.EnableMigrationsCommand.<>c__DisplayClass2.<.ctor>b__0() 
    at System.Data.Entity.Migrations.MigrationsDomainCommand.Execute(Action command) 

EDIT2:

<connectionStrings> 
    <add name="DatabaseContext" providerName="System.Data.SqlServerCe.4.0" connectionString="Data Source=SOM_db.sdf;Max Database Size=1024" /> 
    </connectionStrings> 
+0

Có vẻ như bạn đang sử dụng công cụ sai cho lớp kiên trì của mình. Bạn có nghĩ về giải pháp NoSQL không? –

+0

@raderick Đây không phải là một lựa chọn .... – Flo

+0

Bạn đã thử cập nhật tought bảng điều khiển quản lý gói PowerShell hoặc nuget, sử dụng Update-Database -Verbose chưa? Ngoài ra, liệu tham chiếu null có trỏ đến bảng mới được tạo bởi quá trình di chuyển không? – GaelSa

Trả lời

5

Bạn đang yêu cầu điều gì là có thể thực hiện được, nhưng có một số hạn chế.

Giải pháp:

Thứ nhất, loại bỏ các

Database.Initialize(true); 

từ các nhà xây dựng. Hàm tạo được gọi nhiều lần, bao gồm di chuyển.

Thứ hai, tạo ra một lớp cấu hình như thế này

internal sealed class DataContextConfiguration : DbMigrationsConfiguration<DataContext> 
{ 
    public DataContextConfiguration() 
    { 
     AutomaticMigrationsEnabled = true; 
     AutomaticMigrationDataLossAllowed = true; 
     ContextKey = "DataContext"; 
    } 
} 

Sau đó thay đổi các nhà xây dựng như sau:

public DataContext() 
{ 
    Database.SetInitializer(new MigrateDatabaseToLatestVersion<DataContext, DataContextConfiguration>()); 
} 

và bạn đã làm xong. Các bảng cơ sở dữ liệu cho các loại thực thể từ các plugin sẽ tự động được tạo/cập nhật cho phù hợp.

Tóm lại, về cơ bản đây là phương pháp tiếp cận Mã đầu tiên tiêu chuẩn được bật tự động nhưng có đăng ký/cấu hình loại thực thể động từ bên trong ghi đè OnModelCreating.

Hạn chế:

  • Nếu bạn không đặt AutomaticMigrationDataLossAllowed = true, khi các plugin hiện được lấy ra, EF sẽ tạo ra ngoại lệ vì nó không được phép xóa các bảng tương ứng. Và nếu bạn làm như vậy, các bảng plugin sẽ bị xóa, vì vậy nếu plugin được thêm một lần nữa, nó sẽ bắt đầu từ số không.

  • Các thực thể plugin chỉ có thể được định cấu hình bằng cách sử dụng Chú thích dữ liệu. Nếu bạn muốn cung cấp cho họ toàn quyền kiểm soát, bạn có thể cần phải thay đổi giao diện plugin và thay vì dùng các loại thực thể, thay vào đó hãy gọi một số phương thức và chuyển số DbModelBuilder để họ có thể sử dụng API thông thạo để định cấu hình các loại thực thể của họ.

+0

Cảm ơn bạn !!! Nó đang làm việc! Chỉ một câu hỏi: Tôi không muốn ef đó xóa các bảng, nếu plugin bị xóa! Bạn có ý tưởng gì không? – Flo

+1

Đó là một vấn đề như tôi đã đề cập. Nếu bạn không đăng ký loại thực thể, EF giả định rằng nó đã bị xóa. Nếu bạn không đặt tùy chọn đã nói ở trên (mặc định là 'false'), bạn sẽ nhận được ngoại lệ. Thật không may AFAIK không có tùy chọn cho phép bạn để lại các bảng hiện có. Vì vậy, bạn nhận được tất cả hoặc không có gì: ( –

+0

Được rồi cảm ơn bạn rất nhiều! – Flo

0

Tôi không nghĩ rằng nó sẽ đã từng làm việc với EF6 bằng cách sử dụng phương pháp này.

EF cần DbSets nằm trong lớp ngữ cảnh, do đó bạn cần tạo lớp học DatabaseContext khi đang chạy (dựa trên các thực thể plugin), biên dịch và tải nó. Sau đó, bạn có thể bắt đầu suy nghĩ về việc di chuyển (tự động hoặc thủ công, có hoặc không cho phép mất dữ liệu và vân vân).
Cũng sử dụng vừa tạo DatabaseContext của bạn nên được đơn giản (bạn sẽ có thể làm mọi việc truy cập đến lớp học của bạn thông qua giao diện tiêu chuẩn DbContext)

1

Run:

Update-Database –Verbose 

Nếu nó không thành công, hãy dán những thông điệp như một lời bình luận.

Các vấn đề liên quan