2015-02-24 23 views
7

Verilen bir DbContext türü için Varlık Çerçevesi MetadataWorkspace'u geçmesi gereken bir sınama kitaplığı yazıyorum. Ancak, bu bir test kütüphanesi olduğu için, veritabanına bir bağlantım olmamasını tercih ediyorum - test ortamından temin edilemeyen bağımlılıkları ortaya koyar. Bir veritabanına bağlantı olmadan bir MetadataWorkspace almak mümkün mü?

ben şöyle MetadataWorkspace bir referans elde etmeye çalışmak

:

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)

bir bağlantı dizesi olmadan İstediğimi yapmak mümkün mü:

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

Ben SqlException olsun?

+0

Bağlamı nasıl başlatırsınız? –

+0

@GertArnold Parametre olmayan bir kurucu kullanıyorum – AlexFoxGill

cevap

7

Evet, bağlamı bir taklit bağlantı dizesi besleyerek bunu yapabilirsiniz. Genellikle, DbContext'in parametresiz yapıcısını çağırdığınızda, ana dizinin app.config dosyasında bağlam sınıfınızın adıyla bağlantı dizesini arayacağını unutmayın. Durum buysa ve bu davranışı değiştiremiyorsanız (söz konusu bağlamın kaynak koduna sahip olmadığınız gibi) - bu aplike bağlantı dizesiyle app.config dosyasını güncellemeniz gerekecektir (çalışma zamanında da yapılabilir). Sonra bağlantı dizesi ile DBContext yapıcısı diyebilirsen:

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);     
} 

Yani meta çalışma alanını elde etmek için önemli sadece parametrelerin sağlanması ve boş bağlantı dize sağlamaktadır.

GÜNCELLEME: daha fazla düşündükten sonra, bu tür korsanları kullanmanız ve bağlamı başlatmanız gerekmez.

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}); 
} 

Burada sadece incelemek için montaj da o meta elemanlarını hedef yollarının aktarımı, doğrudan MetadataWorkspace sınıfının kurucu ve. Bu yöntemin bazı varsayımlar yaptığına dikkat edin: meta veri yapay kaynaklarının kaynaklara (genellikle bunlar, ancak dışsal veya başka bir yol altında gömülebilir) gömülü olduğu ve gereken her şeyin Bağlam sınıfının kendisi ile aynı mecrada olduğu (teoride olabilirsiniz) Bir mecliste bağlam ve başka bir varlık sınıfı veya bir şey). Ama umarım fikrini alırsın.

UPDATE2: Kod modeli ilkesinde meta veri çalışma alanı almak daha karmaşıktır, çünkü bu model için edmx dosyası çalışma zamanında oluşturulur. Nerede ve nasıl üretildiği, uygulama detaylandırmasıdır. Ancak, bazı çabalarla metadata çalışma alanı elde edebilirsiniz:

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

Bu umut verici görünüyor ancak bir MetadataException alıyorum: "Belirtilen meta veri kaynağını yükleyemiyorum." - Tam yığın izi [burada] (http://pastebin.com/raw/4kdNqCmk). Herhangi bir fikir? – AlexFoxGill

+0

Yukarıdaki yöntemlerden hangisini kullanarak? – Evk

+0

Üzgünüm - bu her iki yöntemi de kullanıyor. EF6 Veritabanı-İlk önce bu yardımcı olur – AlexFoxGill

İlgili konular