2016-11-29 1 views
0

Ich habe einige Word-Vorlagen (vielleicht Tausende). Jede Vorlage hat Zusammenführungsfelder, die aus der Datenbank gefüllt werden. Ich mag es nicht, separaten Code für jede Vorlage zu schreiben und dann die Anwendung zu erstellen und zu implementieren, wenn eine Vorlage geändert oder ein Feld in der Vorlage hinzugefügt wird!Erstellen Sie dynamische LINQ-Abfragen aus einer Zeichenfolge - Verwenden Sie Reflection?

Stattdessen versuche ich alle Merge-Felder in einer separaten XML-Datei zu definieren und für jedes Feld möchte ich die "Abfrage" schreiben, die bei Bedarf aufgerufen wird. EX:

  1. mergefield1 wird Abfrage "Case.Parties.FirstOrDefault.NameEn"
  2. mergefield2 nennen Abfrage "Case.CaseNumber"
  3. mergefield3 rufen Abfrage „Case.Documents.FirstOrDefault.DocumentContent.DocumentType nennen "
  4. Etc,

Also, für eine bestimmte Vorlage scannen ich seine Druckfelder, und für jedes Feld fusioniert ich nehme es` s ‚Abfragedefinition‘ und diese Anforderung an Datenbank machen EntityFramework und LINQ verwenden. Ex. es funktioniert für diese Abfragen: "TimeSlots.FirstOrDefault.StartDateTime" oder "Case.CaseNumber"

Dies wird eine Engine sein, die Word-Dokumente generiert und füllt es mit Seriendruckfeldern aus XML. Darüber hinaus funktioniert es für jede neue Vorlage oder neues Zusammenführungsfeld.

Jetzt habe ich eine Version mit Reflektion gearbeitet.

public string GetColumnValueByObjectByName(Expression<Func<TEntity, bool>> filter = null, string objectName = "", string dllName = "", string objectID = "", string propertyName = "") 
    { 
     string objectDllName = objectName + ", " + dllName; 
     Type type = Type.GetType(objectDllName); 
     Guid oID = new Guid(objectID); 
     dynamic Entity = context.Set(type).Find(oID); // get Object by Type and ObjectID 

     string value = ""; //the value which will be filled with data from database 

     IEnumerable<string> linqMethods = typeof(System.Linq.Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public).Select(s => s.Name).ToList(); //get all linq methods and save them as list of strings 

     if (propertyName.Contains('.')) 
     { 
      string[] properies = propertyName.Split('.'); 
      dynamic object1 = Entity; 
      IEnumerable<dynamic> Child = new List<dynamic>(); 
      for (int i = 0; i < properies.Length; i++) 
      { 
       if (i < properies.Length - 1 && linqMethods.Contains(properies[i + 1])) 
       { 
        Child = type.GetProperty(properies[i]).GetValue(object1, null); 
       } 
       else if (linqMethods.Contains(properies[i])) 
       { 
        object1 = Child.Cast<object>().FirstOrDefault(); //for now works only with FirstOrDefault - Later it will be changed to work with ToList or other linq methods 
        type = object1.GetType(); 
       } 
       else 
       { 
        if (linqMethods.Contains(properies[i])) 
        { 
         object1 = type.GetProperty(properies[i + 1]).GetValue(object1, null); 
        } 
        else 
        { 
         object1 = type.GetProperty(properies[i]).GetValue(object1, null); 
        } 
        type = object1.GetType(); 
       } 
      } 

      value = object1.ToString(); //.StartDateTime.ToString(); 
     } 

     return value; 
    } 

Ich bin mir nicht sicher, ob dies der beste Ansatz ist. Hat jemand einen besseren Vorschlag oder hat jemand schon so etwas gemacht?

Um es zu kürzen: Die Idee ist es, generische linq Abfragen an die Datenbank aus einer Zeichenfolge wie: "Case.Parties.FirstOrDefault.NameEn".

+0

Wenn ich Sie auf die richtige Art und Weise verstehe, würde ich Ihnen die Verwendung von Expression zum Erstellen von LINQ-Abfrage empfehlen.Diese Dinge können Sie erstellen, linq Anfrage in Laufzeit. https://msdn.microsoft.com/ru-ru/library/mt654263.aspx - hier ist ein Beispiel – Egorikas

+0

Danke Egorikas. Eigentlich sind Expression ein bisschen komplex. Und ich bin mir nicht sicher, ob das auch auf mein Problem zutrifft. Aber ich werde noch einmal auf Ausdrücke schauen. – drill

Antwort

0

Ihr Ansatz ist sehr gut. Ich habe keinen Zweifel, dass es bereits funktioniert.

Ein anderer Ansatz ist die Verwendung von Expression Tree wie @Egorikas vorgeschlagen haben.

Haftungsausschluss: Ich bin der Besitzer des Projekts Eval-Expression.NET

Kurz gesagt, diese Bibliothek ermöglicht es Ihnen, fast jeden C# Code zur Laufzeit zu bewerten (was Sie genau tun wollen).

Ich würde vorschlagen, dass Sie stattdessen meine Bibliothek verwenden.Um den Code zu halten:

  • lesbarer
  • Leichter zu unterstützen
  • eine gewisse Flexibilität hinzufügen

Beispiel

public string GetColumnValueByObjectByName(Expression<Func<TEntity, bool>> filter = null, string objectName = "", string dllName = "", string objectID = "", string propertyName = "") 
{ 
    string objectDllName = objectName + ", " + dllName; 
    Type type = Type.GetType(objectDllName); 
    Guid oID = new Guid(objectID); 
    object Entity = context.Set(type).Find(oID); // get Object by Type and ObjectID 

    var value = Eval.Execute("x." + propertyName, new { x = entity }); 
    return value.ToString(); 
} 

Die Bibliothek erlaubt Ihnen auch mit IQueryable dynamische Zeichenfolge zu verwenden

Wiki: LINQ-Dynamic

Verwandte Themen