2015-11-26 10 views
5

मुझे पता है कि यह प्रश्न पहले ही पूछा जा चुका है लेकिन मुझे कोई जवाब नहीं मिला जो मुझे संतुष्ट करता है। मैं जो करने की कोशिश कर रहा हूं वह अपने प्रकार के नाम के आधार पर एक विशेष DbSet<T> पुनर्प्राप्त करना है।डीबीसीएन्टेक्स्ट में एक सामान्य डीबीसेट ढूंढें गतिशील रूप से

[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("MyDllAssemblyName")] 
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("MyCallingAssemblyName")] 

class MyDbContext : DbContext { 

    public DbSet<ModelA> A { get; set; } 
    public DbSet<ModelB> B { get; set; } 

    public dynamic GetByName_SwitchTest(string name) { 
     switch (name) { 
      case "A": return A; 
      case "B": return B; 
     } 
    } 

    public dynamic GetByName_ReflectionTest(string fullname) 
    { 
     Type targetType = Type.GetType(fullname); 
     var model = GetType() 
      .GetRuntimeProperties() 
      .Where(o => 
       o.PropertyType.IsGenericType && 
       o.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>) && 
       o.PropertyType.GenericTypeArguments.Contains(targetType)) 
      .FirstOrDefault(); 
     if (null != model) 
      return model.GetValue(this); 
     return null; 
    } 
} 

मैं कोई परेशानी नहीं प्रकार ही है कि क्या यह एक सरल स्विच या प्रतिबिंब के माध्यम से है हो रही है:

मैं निम्नलिखित है। हालांकि मुझे गति को गतिशील के रूप में वापस करने की आवश्यकता है क्योंकि मुझे नहीं पता कि डीबीसेट प्रकार क्या होगा।

// MyDbContext MyDbContextInstance.. 
var model = MyDbContextInstance.GetByName_SwitchTest("A"); 
var record1 = model.FirstOrDefault(); // It crashes here with RunTimeBinderException 

इस बिंदु model पर एक InternalDbSet<ModelA> प्रकार का एक उदाहरण में शामिल हैं: तो कहीं और ही विधानसभा में, मैं इसे इस तरह से इस्तेमाल करते हैं। वहाँ से, किसी भी उपयोग मैं model वस्तु के साथ क्या मैं एक RunTimeBinderException मिलती है: 'Microsoft.Data.Entity.Internal.InternalDbSet' 'FirstOrDefault'

वेब पर जांच के लिए एक परिभाषा शामिल नहीं है, मैं एक blog post पाया यह बताता है कि (अपने ब्लॉग दीक्षित):

कारण FirstOrDefault करने के लिए कॉल() विफल रहता है कि मॉडल के प्रकार जानकारी रनटाइम पर उपलब्ध नहीं है। कारण यह उपलब्ध नहीं है क्योंकि अनाम प्रकार सार्वजनिक नहीं हैं। जब विधि उस अज्ञात प्रकार का उदाहरण लौटा रही है, तो यह सिस्टम लौटा रही है। ऑब्जेक्ट जो अज्ञात प्रकार के उदाहरण का संदर्भ देता है - टाइप करें जिसका जानकारी मुख्य प्रोग्राम में उपलब्ध नहीं है।

और फिर उसने बताते हैं कि एक समाधान:

समाधान वास्तव में बहुत सरल है। [assembly:InternalsVisibleTo("assembly-name")]

मैं अपने कोड पर इस समाधान की कोशिश की थी, लेकिन यह काम नहीं करता: सभी हम क्या करना है ClassLibrary1 परियोजना के AssemplyInfo.cs को खोलने और उसमें निम्न पंक्ति जोड़ने है। जानकारी के लिए मेरे पास एएसपीनेट 5 समाधान है जिसमें डीएनएक्स डॉटनेट 46 पर चल रहे दो असेंबली हैं। एक ऐप और एक डीएल जिसमें मेरे सभी मॉडल और डीबीकॉन्टेक्स्ट शामिल हैं। मेरे द्वारा किए गए सभी संबंधित कॉल हालांकि डीएल पर स्थित हैं।

क्या इस समाधान के पास काम करने का कोई मौका है? क्या मुझे कुछ याद आ रही है? किसी भी पॉइंटर्स की सराहना की जाएगी?

अग्रिम धन्यवाद

[संपादित करें]

मैं IQueryable<dynamic> बजाय dynamic वापसी की कोशिश की है और मैं मूल क्वेरी कर सकता है model.FirstOrDefault();लेकिन सब से ऊपर मैं करने में सक्षम होना चाहते हैं एक मैदान पर भी फिल्टर करें:

var record = model.FirstOrDefault(item => item.MyProperty == true); 
+0

होगा कैसे परिवर्तन के बारे में IEnumerable को गतिशील? – Kelmen

+0

मैंने कुछ ऐसा करने की कोशिश की (IQueryable में बदला गया) और भले ही मैं 'मॉडल.फर्स्टऑर्डफॉल्ट()' जैसे कुछ प्रश्न पूछ सकूं, यह मुझे 'मॉडल' जैसी चीज़ों को करने की अनुमति नहीं देगा। फर्स्टऑर्डडिफॉल्ट (item => item.MyProperty = = सत्य) '। जो चीज की उपयोगिता को कम कर देता है। – DarkUrse

+0

मैंने इस समस्या में भाग लिया है। कोई प्रस्ताव है कि आप एक संकल्प तक पहुंच गए हैं? – JosephGarrone

उत्तर

0

* अस्वीकरण: यह प्रतिक्रिया मेरे प्रश्न के लिए एक कठोर सेंसू जवाब नहीं देती है। यह मेरी अपनी समस्या को हल करने के लिए एक अलग दृष्टिकोण है।मुझे पता है कि यह किसी दिए गए परिस्थिति के लिए एक विशिष्ट उदाहरण है जो हर किसी के लिए काम नहीं करेगा। मैं उम्मीद में इस दृष्टिकोण को पोस्ट कर रहा हूं कि यह किसी की मदद करता है लेकिन इसे उत्तर के रूप में चिह्नित नहीं करेगा क्योंकि मैं अभी भी एक वास्तविक समाधान की उम्मीद कर रहा हूं।

के साथ शुरू करने के लिए, के तथ्य यह है केवल उपयोगी जानकारी हम वर्तमान कोड से बाहर निकल सकते एक रिकार्ड मौजूद है या नहीं .. उसके बाद एक गतिशील प्रश्नों के किसी भी प्रयास RuntimeBinderException देना होगा को स्वीकार करते हैं।

तो चलो एक और तथ्य जारी रखें; DbContext.Add (ऑब्जेक्ट) और DbContext.Update (ऑब्जेक्ट) टेम्पलेट आधारित नहीं हैं, इसलिए हम उन्हें अपने मॉडल को सहेजने के लिए उपयोग कर सकते हैं (db.A.Add() या db.A.Update() के बजाय

इन अपने ही स्थिति, कोई और अधिक एक प्रक्रिया

  1. मॉडल एक छोटे से परिभाषित बाहर काम करने के लिए आवश्यक है अलग ढंग से

साथ, मैं एक क्षेत्र है कि मेरे सभी मॉडल जो स्पष्ट रूप से एक होना चाहिए भर में पुनः प्राप्त करने योग्य है की जरूरत है शुरू करने के लिए एक अद्वितीय रिकॉर्ड की पहचान करने के लिए रास्ता।

// IModel give me a reliable common field to all my models (Fits my DB design maybe not yours though) 
interface IModel { Guid Id { get; set; } } 

// ModelA inherit IModel so that I always have access to an 'Id' 
class ModelA : IModel { 
    public Guid Id { get; set; } 
    public int OtherField { get; set; } 
} 

// ModelB inherit IModel so that I always have access to an 'Id' 
class ModelB : IModel { 
    public Guid Id { get; set; } 
    public string WhateverOtherField { get; set; } 
} 
  1. फिर से उद्देश्य गतिशील थोड़ा प्रश्नों हम कुछ काम करता है

मैं स्मार्ट क्वेरी गतिशील करने के लिए एक रास्ता नहीं मिला है पता करने के लिए है, तो इसके बजाय मुझे पता है कि मैं विश्वसनीय रूप से एक रिकॉर्ड की पहचान कर सकता हूं और जान सकता हूं कि यह मौजूद है या नहीं।

class MyDbContext : DbContext { 

    public DbSet<ModelA> A { get; set; } 
    public DbSet<ModelB> B { get; set; } 

    // In my case, this method help me to know the next action I need to do 
    // The switch/case option is not pretty but might have better performance 
    // than Reflection. Anyhow, this is one's choice. 
    public bool HasRecord_SwitchTest(string name) { 
     switch (name) { 
      case "A": return A.AsNoTracking().Any(o => o.Id == id); 
      case "B": return B.AsNoTracking().Any(o => o.Id == id); 
     } 
     return false; 
    } 

    // In my case, this method help me to know the next action I need to do 
    public bool HasRecord_ReflectionTest(string fullname) 
    { 
     Type targetType = Type.GetType(fullname); 
     var model = GetType() 
      .GetRuntimeProperties() 
      .Where(o => 
       o.PropertyType.IsGenericType && 
       o.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>) && 
       o.PropertyType.GenericTypeArguments.Contains(targetType)) 
      .FirstOrDefault(); 
     if (null != model) 
      return (bool)model.GetValue(this).AsNoTracking().Any(o => o.Id == id); 
     return false; 
    } 

    // Update and save immediately - simplified for example 
    public async Task<bool> UpdateDynamic(object content) 
    { 
     EntityEntry entry = Update(content, GraphBehavior.SingleObject); 
     return 1 == await SaveChangesAsync(true); 
    } 

    // Insert and save immediately - simplified for example 
    public async Task<bool> InsertDynamic(object content) 
    { 
     EntityEntry entry = Add(content, GraphBehavior.SingleObject); 
     return 1 == await SaveChangesAsync(true); 
    } 
} 
  • पाइपलाइन का एक छोटा सा एक तरह से मेरी स्थिति
  • इसके बाद, क्या मुझे लगता है कि गतिशील प्रश्नों के साथ क्या करना जरूरी था करने के लिए एक बोध कराने के लिए दोहराने के लिए

      एक सर्वर से डेटा मेरे ग्राहक के लिए नीचे। (मैं इस उदाहरण को आसान बनाने की वास्तुकला का एक बड़ा हिस्सा निकाल दी हैं)

      class ReplicationItem 
      { 
          public ReplicationAction Action { get; set; } // = Create, Update, Delete 
          public string ModelName { get; set; } // Model name 
          public Guid Id { get; set; } // Unique identified across whole platform 
      } 
      
      1. बिट्स कनेक्ट।

      अब, यहाँ दिनचर्या बिट्स

      जोड़ता है है
      public async void ProcessReplicationItem(ReplicationItem replicationItem) 
      { 
          using (var db = new MyDbContext()) 
          { 
           // Custom method that attempts to get remote value by Model Name and Id 
           // This is where I get the strongly typed object 
           var remoteRecord = await TryGetAsync(replicationItem.ModelName, replicationItem.Id); 
           bool hasRemoteRecord = remoteRecord.Content != null; 
      
           // Get to know if a local copy of this record exists. 
           bool hasLocalRecord = db.HasRecord_ReflectionTest(replicationItem.ModelName, replicationItem.Id); 
      
           // Ensure response is valid whether it is a successful get or error is meaningful (ie. NotFound) 
           if (remoteRecord.Success || remoteRecord.ResponseCode == System.Net.HttpStatusCode.NotFound) 
           { 
            switch (replicationItem.Action) 
            { 
             case ReplicationAction.Create: 
             { 
              if (hasRemoteRecord) 
              { 
               if (hasLocalRecord) 
                await db.UpdateDynamic(remoteRecord.Content); 
               else 
                await db.InsertDynamic(remoteRecord.Content); 
              } 
              // else - Do nothing 
              break; 
             } 
             case ReplicationAction.Update: 
              [etc...] 
            } 
           } 
          } 
      } 
      
      // Get record from server and with 'response.Content.ReadAsAsync' type it 
      // already to the appropriately 
      public static async Task<Response> TryGetAsync(ReplicationItem item) 
      { 
          if (string.IsNullOrWhiteSpace(item.ModelName)) 
          { 
           throw new ArgumentException("Missing a model name", nameof(item)); 
          } 
      
          if (item.Id == Guid.Empty) 
          { 
           throw new ArgumentException("Missing a primary key", nameof(item)); 
          } 
      
          // This black box, just extrapolate a uri based on model name and id 
          // typically "api/ModelA/{the-guid}" 
          string uri = GetPathFromMessage(item); 
      
          using (var client = new HttpClient()) 
          { 
           client.BaseAddress = new Uri("http://localhost:12345"); 
      
           HttpResponseMessage response = await client.GetAsync(uri); 
           if (response.IsSuccessStatusCode) 
           { 
            return new Response() 
            { 
             Content = await response.Content.ReadAsAsync(Type.GetType(item.ModelName)), 
             Success = true, 
             ResponseCode = response.StatusCode 
            }; 
           } 
           else 
           { 
            return new Response() 
            { 
             Success = false, 
             ResponseCode = response.StatusCode 
            }; 
           } 
          } 
      } 
      
      public class Response 
      { 
          public object Content { get; set; } 
          public bool Success { get; set; } 
          public HttpStatusCode ResponseCode { get; set; } 
      } 
      

      पुनश्च: मैं अभी भी एक असली जवाब में दिलचस्पी है, तो अन्य उत्तर के लिए पोस्टिंग यदि आप साझा करने के लिए एक असली एक है रखें ।

    0

    तो संकलन समय के दौरान मुझे <T> के बारे में पता नहीं होने पर मैंने यह कैसे किया। के रूप में DbContext.Set विधि संदर्भ में दिए गए प्रकार और अंतर्निहित दुकान के संस्थाओं के लिए उपयोग करने के लिए एक गैर सामान्य DbSet उदाहरण रिटर्न प्रकार प्राप्त करने के लिए

    पहले की जरूरत है।

    public virtual DbSet Set(Type entityType) 
    

    नोट यहां तर्क इकाई का प्रकार है जिसके लिए एक सेट वापस किया जाना चाहिए। और दिए गए इकाई प्रकार के लिए सेट वापसी मूल्य है।

    var type = Assembly.GetExecutingAssembly().GetTypes().FirstOrDefault(t => t.Name == <Pass your table name>); 
    

    अब एक बार मैं इस प्रकार के

    if(type != null) 
    { 
    DbSet context = context.Set(type); 
    } 
    

    या एक एक लाइनर

    DbSet mySet = context.Set(Type.GetType("<Your Entity Name>")); 
    
    +1

    आपके उत्तर के लिए धन्यवाद। हालांकि - 'सार्वजनिक आभासी डीबीसेट सेट (प्रकार इकाई टाइप) '- अब इकाई फ्रेमवर्क 7 के साथ मौजूद नहीं है। उस पर शीर्ष पर,' डीबीसेट 'मुझे मॉडल पर धाराप्रवाह एपीआई प्रश्न करने की अनुमति नहीं देगा। – DarkUrse

    संबंधित मुद्दे