2015-02-24 18 views
7

Tôi đang viết một thư viện kiểm tra cần phải đi qua Khung thực thể MetadataWorkspace đối với loại DbContext nhất định. Tuy nhiên, vì đây là thư viện kiểm thử nên tôi không muốn có kết nối đến cơ sở dữ liệu - nó giới thiệu các phụ thuộc có thể không có sẵn từ môi trường thử nghiệm.Có thể truy xuất MetadataWorkspace mà không cần kết nối với cơ sở dữ liệu không?

Khi tôi cố gắng để có được một tham chiếu đến MetadataWorkspace như vậy:

var metadata = ((IObjectContextAdapter)context).ObjectContext.MetadataWorkspace; 

tôi nhận được một SqlException:

An exception of type 'System.Data.SqlClient.SqlException' occurred in System.Data.dll but was not handled in user code

Additional information: A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)

Có thể làm những gì tôi muốn mà không có một chuỗi kết nối?

+0

Làm thế nào để bạn khởi tạo 'ngữ cảnh '? –

+0

@GertArnold Tôi chỉ sử dụng một hàm tạo parameterless – AlexFoxGill

Trả lời

7

Có, bạn có thể thực hiện việc này bằng cách cung cấp ngữ cảnh chuỗi kết nối giả. Lưu ý rằng thường khi bạn gọi constructor parameterless của DbContext, nó sẽ tìm chuỗi kết nối với tên của lớp ngữ cảnh của bạn trong tệp app.config của ứng dụng chính. Nếu đó là trường hợp và bạn không thể thay đổi hành vi này (như bạn không sở hữu mã nguồn của ngữ cảnh đang được đề cập đến) - bạn sẽ phải cập nhật app.config với chuỗi conneciton giả đó (có thể được thực hiện trong thời gian chạy). Nếu bạn có thể gọi hàm tạo DbContext bằng chuỗi kết nối, thì:

var cs = String.Format("metadata=res://*/{0}.csdl|res://*/{0}.ssdl|res://*/{0}.msl;provider=System.Data.SqlClient;provider connection string=\"\"", "TestModel"); 
using (var ctx = new TestDBEntities(cs)) { 
    var metadata = ((IObjectContextAdapter)ctx).ObjectContext.MetadataWorkspace; 
    // no throw here 
    Console.WriteLine(metadata);     
} 

Vì vậy, bạn chỉ cung cấp thông số quan trọng để lấy không gian làm việc siêu dữ liệu và cung cấp chuỗi kết nối trống.

CẬP NHẬT: sau khi suy nghĩ thêm, bạn không cần phải sử dụng các hack như vậy và tạo bối cảnh ngay lập tức.

public static MetadataWorkspace GetMetadataWorkspaceOf<T>(string modelName) where T:DbContext { 
    return new MetadataWorkspace(new[] { $"res://*/{modelName}.csdl", $"res://*/{modelName}.ssdl", $"res://*/{modelName}.msl" }, new[] {typeof(T).Assembly}); 
} 

Ở đây bạn chỉ cần sử dụng hàm tạo của lớp MetadataWorkspace trực tiếp, chuyển đường dẫn đến mục tiêu siêu dữ liệu và cũng được lắp ráp để kiểm tra. Lưu ý rằng phương thức này đưa ra một số giả định: các tạo phẩm siêu dữ liệu được nhúng vào các tài nguyên (thường là chúng, nhưng có thể ở bên ngoài hoặc được nhúng dưới một đường dẫn khác) và tất cả mọi thứ cần thiết trong cùng một assembly như lớp Ngữ cảnh (bạn có thể có lý thuyết) bối cảnh trong một hội đồng và các lớp thực thể khác, hoặc một cái gì đó). Nhưng tôi hy vọng bạn có được ý tưởng.

UPDATE2: để lấy không gian làm việc siêu dữ liệu của mô hình mã đầu tiên có phần phức tạp hơn, vì tệp edmx cho mô hình đó được tạo khi chạy. Vị trí và cách thức được tạo ra là chi tiết triển khai. Tuy nhiên, bạn vẫn có thể nhận được không gian làm việc siêu dữ liệu với một số nỗ lực:

public static MetadataWorkspace GetMetadataWorkspaceOfCodeFirst<T>() where T : DbContext { 
     // require constructor which accepts connection string 
     var constructor = typeof (T).GetConstructor(new[] {typeof (string)}); 
     if (constructor == null) 
      throw new Exception("Constructor with one string argument is required."); 
     // pass dummy connection string to it. You cannot pass empty one, so use some parameters there 
     var ctx = (DbContext) constructor.Invoke(new object[] {"App=EntityFramework"}); 
     try {     
      var ms = new MemoryStream(); 
      var writer = new XmlTextWriter(ms, Encoding.UTF8); 
      // here is first catch - generate edmx file yourself and save to xml document 
      EdmxWriter.WriteEdmx(ctx, writer); 
      ms.Seek(0, SeekOrigin.Begin); 
      var rawEdmx = XDocument.Load(ms); 
      // now we are crude-parsing edmx to get to the elements we need 
      var runtime = rawEdmx.Root.Elements().First(c => c.Name.LocalName == "Runtime");     
      var cModel = runtime.Elements().First(c => c.Name.LocalName == "ConceptualModels").Elements().First(); 
      var sModel = runtime.Elements().First(c => c.Name.LocalName == "StorageModels").Elements().First(); 
      var mModel = runtime.Elements().First(c => c.Name.LocalName == "Mappings").Elements().First(); 

      // now we build a list of stuff needed for constructor of MetadataWorkspace 
      var cItems = new EdmItemCollection(new[] {XmlReader.Create(new StringReader(cModel.ToString()))}); 
      var sItems = new StoreItemCollection(new[] {XmlReader.Create(new StringReader(sModel.ToString()))}); 
      var mItems = new StorageMappingItemCollection(cItems, sItems, new[] {XmlReader.Create(new StringReader(mModel.ToString()))}); 
      // and done 
      return new MetadataWorkspace(() => cItems,() => sItems,() => mItems); 
     } 
     finally { 
      ctx.Dispose(); 
     } 
    } 
+0

Điều này có vẻ đầy hứa hẹn nhưng tôi nhận được một MetadataException: "Không thể tải tài nguyên siêu dữ liệu được chỉ định." - dấu vết ngăn xếp đầy đủ [ở đây] (http://pastebin.com/raw/4kdNqCmk). Bất kỳ ý tưởng? – AlexFoxGill

+0

Sử dụng phương pháp nào ở trên? – Evk

+0

Xin lỗi - đó là sử dụng một trong hai phương pháp. Cơ sở dữ liệu EF6-đầu tiên nếu điều đó giúp – AlexFoxGill

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