2012-06-07 27 views
6

Sử dụng khung pháp nhân 4.3.1 Mã đầu tiên và Di chuyển dữ liệu.Làm cách nào để ghi đè tập lệnh SQL được tạo bởi MigratorScriptingDecorator

Tôi đã viết một tiện ích để tự động tạo tập lệnh di chuyển cho cơ sở dữ liệu đích, sử dụng MigratorScriptingDecorator.

Tuy nhiên, đôi khi khi tạo lại cơ sở dữ liệu đích từ đầu, tập lệnh được tạo không hợp lệ, trong đó nó khai báo biến có cùng tên hai lần.

Tên biến là @ var0.

Điều này dường như xảy ra khi có nhiều lần di chuyển được áp dụng và khi ít nhất hai kết quả trong giới hạn mặc định bị loại bỏ.

Vấn đề xảy ra cả khi tạo mã hình thức kịch bản, và khi sử dụng Package Manager console lệnh:

Update-Database -Script 

Dưới đây là các đoạn vi phạm hình thức kịch bản được tạo ra:

DECLARE @var0 nvarchar(128) 
SELECT @var0 = name 
FROM sys.default_constraints 
WHERE parent_object_id = object_id(N'SomeTableName') 

DECLARE @var0 nvarchar(128) 
SELECT @var0 = name 
FROM sys.default_constraints 
WHERE parent_object_id = object_id(N'SomeOtherTableName') 

Tôi muốn có thể ghi đè điểm mà địa điểm đó nerates SQL cho mỗi di chuyển, và sau đó thêm một "GO" tuyên bố để mỗi di chuyển là trong một lô riêng biệt, mà sẽ giải quyết vấn đề.

Bất cứ ai có ý tưởng làm thế nào để làm điều này, hoặc nếu tôi sủa cây sai thì có lẽ bạn có thể đề xuất một cách tiếp cận tốt hơn?

Trả lời

4

Vì vậy, với việc sử dụng rộng rãi ILSpy và một số con trỏ trong the answer to this question Tôi đã tìm được cách.

Chi tiết bên dưới cho những người quan tâm.

Vấn đề

Các SqlServerMigrationSqlGenerator là lớp cuối cùng chịu trách nhiệm cho việc tạo ra các câu lệnh SQL mà có được thực thi dựa trên cơ sở dữ liệu mục tiêu hoặc kịch bản ra khi sử dụng -Script switch trong Package Manager console hoặc khi sử dụng MigratorScriptingDecorator.

hoạt

Thẩm định phương pháp Genearate trong SqlServerMigrationSqlGenerator có trách nhiệm cho một DROP COLUMN, nó trông như thế này:

protected virtual void Generate(DropColumnOperation dropColumnOperation) 
{ 
    RuntimeFailureMethods 
     .Requires(dropColumnOperation != null, null, "dropColumnOperation != null"); 
    using (IndentedTextWriter indentedTextWriter = 
     SqlServerMigrationSqlGenerator.Writer()) 
    { 
     string value = "@var" + this._variableCounter++; 
     indentedTextWriter.Write("DECLARE "); 
     indentedTextWriter.Write(value); 
     indentedTextWriter.WriteLine(" nvarchar(128)"); 
     indentedTextWriter.Write("SELECT "); 
     indentedTextWriter.Write(value); 
     indentedTextWriter.WriteLine(" = name"); 
     indentedTextWriter.WriteLine("FROM sys.default_constraints"); 
     indentedTextWriter.Write("WHERE parent_object_id = object_id(N'"); 
     indentedTextWriter.Write(dropColumnOperation.Table); 
     indentedTextWriter.WriteLine("')"); 
     indentedTextWriter.Write("AND col_name(parent_object_id, 
                 parent_column_id) = '"); 
     indentedTextWriter.Write(dropColumnOperation.Name); 
     indentedTextWriter.WriteLine("';"); 
     indentedTextWriter.Write("IF "); 
     indentedTextWriter.Write(value); 
     indentedTextWriter.WriteLine(" IS NOT NULL"); 
     indentedTextWriter.Indent++; 
     indentedTextWriter.Write("EXECUTE('ALTER TABLE "); 
     indentedTextWriter.Write(this.Name(dropColumnOperation.Table)); 
     indentedTextWriter.Write(" DROP CONSTRAINT ' + "); 
     indentedTextWriter.Write(value); 
     indentedTextWriter.WriteLine(")"); 
     indentedTextWriter.Indent--; 
     indentedTextWriter.Write("ALTER TABLE "); 
     indentedTextWriter.Write(this.Name(dropColumnOperation.Table)); 
     indentedTextWriter.Write(" DROP COLUMN "); 
     indentedTextWriter.Write(this.Quote(dropColumnOperation.Name)); 
     this.Statement(indentedTextWriter); 
    } 
} 

Bạn có thể nhìn thấy nó theo dõi những tên biến được sử dụng, nhưng điều này chỉ xuất hiện để theo dõi trong một lô, tức là di chuyển đơn lẻ. Vì vậy, nếu một migratin chứa nhiều hơn một DROP COLUM các công trình trên tốt, nhưng nếu có hai di chuyển dẫn đến việc tạo DROP COLUMN thì biến số _variableCounter được đặt lại.

Không gặp vấn đề gì khi không tạo tập lệnh, vì mỗi câu lệnh được thực hiện ngay lập tức đối với cơ sở dữ liệu (tôi đã kiểm tra bằng SQL Profiler).

Nếu bạn tạo tập lệnh SQL và muốn chạy tập lệnh đó là mặc dù bạn gặp sự cố.

Giải pháp

Tôi tạo ra một mới BatchSqlServerMigrationSqlGenerator kế thừa từ SqlServerMigrationSqlGenerator như sau (lưu ý bạn cần using System.Data.Entity.Migrations.Sql;):

public class BatchSqlServerMigrationSqlGenerator : SqlServerMigrationSqlGenerator 
{ 
    protected override void Generate 
     (System.Data.Entity.Migrations.Model.DropColumnOperation dropColumnOperation) 
    { 
     base.Generate(dropColumnOperation); 

     Statement("GO"); 
    } 
} 

Bây giờ để buộc các di cư để sử dụng máy phát điện tùy chỉnh của bạn, bạn có hai lựa chọn:

  1. Nếu bạn muốn nó được tích hợp vào t ông Package Manager console, hãy thêm dòng dưới đây để lớp Configuration của bạn:

    SetSqlGenerator("System.Data.SqlClient", 
            new BatchSqlServerMigrationSqlGenerator()); 
    
  2. Nếu bạn đang tạo ra các kịch bản từ mã (như tôi đã được), thêm một dòng tương tự như mã đến nơi mà bạn có lắp ráp cấu hình của bạn trong mã:

    migrationsConfiguration.SetSqlGenerator(DataProviderInvariantName, 
            new BatchSqlServerMigrationSqlGenerator()); 
    
+0

bạn có nghĩ rằng một workaround tương tự có thể có thể cho sql tạo ra cho chèn bảng trực tiếp bình thường không? –

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