Thomas: C# - 2 DataTable vergleichen

Hallo zusammen,

ich selber habe nicht viel Erfahrung in C# und brauche eure Hilfe.

Es geht um folgenden Code:

  
            var l_modifiedRows = newData.Select()  
                                         .Join(  
                                            spData.Select(),  
                                            r => r[keyColumnName],  
                                            r => r[keyColumnName],  
                                            (r1, r2) => new  
                                            {  
                                                Row1 = r1,  
                                                Row2 = r2  
                                            })  
                                        .Where(  
                                            values => !(values.Row1["Vorname"].Equals(values.Row2["Vorname"]) &&  
                                                         values.Row1["Nachname"].Equals(values.Row2["Nachname"])))  
                                        .Select(values => values.Row2);  

Hier werden momentan die Spalten "Vorname" und "Nachname" auf Änderungen geprüft, was auch funktioniert.

Jetzt bekommt die Funktion ein Array übergeben das die Werte (Vorname, Nachname, Alter, Wohnort) beinhaltet. Dieses Array würde ich nun gerne durchlaufen und meine Where Bedingung damit dynamisch aufbauen anstatt "Vorname" und "Nachname" fest anzugeben. Ich weiß momentan aber leider nicht wie ich hier jetzt am besten vorgehe?

Kann mir jemand helfen?

Danke.

Grüße
Thomas

  1. Tach!

    var l_modifiedRows = newData.Select()
                                             .Join(
                                                spData.Select(),
                                                r => r[keyColumnName],
                                                r => r[keyColumnName],
                                                (r1, r2) => new
                                                {
                                                    Row1 = r1,
                                                    Row2 = r2
                                                })
                                            .Where(
                                                values => !(values.Row1["Vorname"].Equals(values.Row2["Vorname"]) &&
                                                             values.Row1["Nachname"].Equals(values.Row2["Nachname"])))
                                            .Select(values => values.Row2);

    
    >   
    > Hier werden momentan die Spalten "Vorname" und "Nachname" auf Änderungen geprüft, was auch funktioniert.  
      
    Statt .Equals() würde ich einfach == nehmen, beziehungsweise hier !=  
      
    
    > Jetzt bekommt die Funktion ein Array übergeben das die Werte (Vorname, Nachname, Alter, Wohnort) beinhaltet. Dieses Array würde ich nun gerne durchlaufen und meine Where Bedingung damit dynamisch aufbauen anstatt "Vorname" und "Nachname" fest anzugeben. Ich weiß momentan aber leider nicht wie ich hier jetzt am besten vorgehe?  
      
    Das heißt, die Werte im Array sind optional und damit auch die Länge der Where-Klausel. Zum einen gibt es "Dynamic Linq", mit dem man die Klausel als String übergeben kann. Dann ist das nur eine Frage der Stringverarbeitung. Zum anderen kannst du den Expression-Tree auch zu Fuß zusammen bauen, was einigermaßen aufwendig ist.  
      
    Ich würde versuchen, die Where-Klauseln einzeln anzuhängen. Zunächst machst du nach dem Join() Schluss und legst das bisherige Ergebnis in einer Variable ab. Je nach Wert im Array hängst du daran jeweils ein Where() an, und anschließend das Select(). Damit sind die Bedingungen aber and-verknüpft. Wenn du or brauchst, dann nimm die Expression-Tree-Methode. Mit den genannten Stichwörtern findest du sicherlich weiteres Material.  
      
      
    dedlfix.
    
    1. Hallo,

      . Mit den genannten Stichwörtern findest du sicherlich weiteres Material.

      dedlfix.

      Vielen Dank, das hilft mir weiter!

      Grüße
      Thomas

      1. Hallo,

        nach langem Suchen und Lesen bin ich leider noch nicht auf eine Lösung meines Problems gekommen. Bei einer "AND" Verkettung ist die Where Klausel kein Problem, für eine "OR" Verkettung allerdings sehe ich kein Licht.

        Ich habe das jetzt ganz einfach so gelöst, dass ich für jede Bedingung ein Select ausführe. Nicht elegant aber funktioniert.

          
        object[,] strArray = getArray();  
        for (int i = 0; i < strArray.GetLength(1); i++)  
        {  
        	var l_modifiedRows = newData.Select()  
        					 .Join(  
        						spData.Select(),  
        						r => r[keyColumnName],  
        						r => r[keyColumnName],  
        						(r1, r2) => new  
        						{  
        							Row1 = r1,  
        							Row2 = r2  
        						})  
        					.Where(  
        						values => !(values.Row1[(string)strArray[0, i]].Equals(values.Row2[(string)strArray[0, i]])))  
        					.Select(values => values.Row2);  
        }  
        
        

        Grüße
        Thomas

        1. Tach!

          nach langem Suchen und Lesen bin ich leider noch nicht auf eine Lösung meines Problems gekommen. Bei einer "AND" Verkettung ist die Where Klausel kein Problem, für eine "OR" Verkettung allerdings sehe ich kein Licht.

          Wie ich schon schrieb, geht das mit einem selbst zusammengestückelten Expression-Tree, ungefähr so.

          dedlfix.

  2. Hallo Thomas,

    folgendes sollte möglich sein

      
    .Where(  
      values => !strArray.All(name => values.Row1[name].Equals(values.Row2[name]))  
    );  
    
    

    oder auch

      
    .Where(  
      values => strArray.Any(name => !values.Row1[name].Equals(values.Row2[name]))  
    );  
    
    

    hth

    1. Tach!

      folgendes sollte möglich sein

      .Where(

      values => strArray.Any(name => !values.Row1[name].Equals(values.Row2[name]))
      );

        
      Ist es auch, zum meinem Erstauen. Da bei einem MS-SQL Server als Datenhaltung die Expression in ein SQL-Statement übersetzt wird, sind nicht alle LINQ-Ausdrücke möglich. Der vorliegende kann aber offenbar übersetzt werden. Das Resultat ist jedoch nicht sehr ansehnlich.  
        
      Mit  
        
        `string[] items = new string[] { "Workitem 2", "Workitem 3" };`{:.language-c}  
        
      liefert ein  
        
        `.Where(t => items.Any(i => i == t.Description))`{:.language-c}  
        
      dieses Monster  
        
      ~~~sql
      SELECT  
      [Extent1].[Id] AS [Id],  
      [Extent1].[Description] AS [Description]  
      FROM [dbo].[TimeCards] AS [Extent1]  
      WHERE  EXISTS (SELECT  
      	1 AS [C1]  
      	FROM  (SELECT  
      		N'Test 1' AS [C1]  
      		FROM  ( SELECT 1 AS X ) AS [SingleRowTable1]  
      	UNION ALL  
      		SELECT  
      		N'Test 2' AS [C1]  
      		FROM  ( SELECT 1 AS X ) AS [SingleRowTable2]) AS [UnionAll1]  
      	WHERE [UnionAll1].[C1] = [Extent1].[Description]  
      )
      

      Zum Vergleich dazu ergibt ein

      .Where(t => t.Description == "Test 1" || t.Description == "Test 2")

      ein übersichtliches

      SELECT  
      [Extent1].[Id] AS [Id],  
      [Extent1].[Description] AS [Description]  
      FROM [dbo].[Tabelle] AS [Extent1]  
      WHERE [Extent1].[Description] IN (N'Test 1',N'Test 2')
      

      Die Frage ist nun, was kostet mehr, die komplexe Query der Any-Variante oder das Erstellen eines Expression-Trees für die ||-Variante.

      P.S: Die zweite Where-Version ließ sich nur mit festen Strings notieren, items[0] und items [1] stattdessen zu verwenden, lässt der LINQ-to-Entities-Mechanismus nicht zu (siehe oben). Beim Zusammenbau eines Expression-Trees stellt das aber kein Problem dar, weil man da einer ConstantExpression mit Typ String einen Wert aus beliebiger Quelle übergeben kann. Und so sähe solch ein Expression-Tree für die zweite Where-Variante aus. Bei mehr Werten müssen entsprechende Equal und verschachtelte OrElse erzeugt werden.

      ParameterExpression paramT = Expression.Parameter(typeof(Tabelle), "t");  
      MemberExpression desc = Expression.PropertyOrField(paramT, "Description");  
      BinaryExpression one = Expression.Equal(desc, Expression.Constant(items[0], typeof(string)));  
      BinaryExpression two = Expression.Equal(desc, Expression.Constant(items[1], typeof(string)));  
      BinaryExpression or = Expression.OrElse(one, two);  
      Expression<Func<Tabelle, bool>> where = Expression.Lambda<Func<Tabelle, bool>>(or, paramT);
      

      dedlfix.

      1. Moin,

        es ging hier doch um DataTable. Nach Select() geht's hier normal mit Linq to Objects weiter. Du meinst vielleicht DbSet und die ganze IQueryable-Geschichte.

        1. Tach!

          es ging hier doch um DataTable. Nach Select() geht's hier normal mit Linq to Objects weiter. Du meinst vielleicht DbSet und die ganze IQueryable-Geschichte.

          Ja, meinte ich. DataTable hab ich noch nie verLINQt. Das scheint mir aber dann nur ein SELECT * gegen die Datenbank zu fahren und die Filterung hinterher vorzunehmen. Nicht sehr effizient. Dann wäre es wohl besser, ein SQL-Statement zu erzeugen oder eine Filter Expression zu verwenden, anstatt das mit LINQ lösen zu wollen.

          dedlfix.