Wie konvertiert man eine DataTable in eine generische Liste?

184

Derzeit verwende ich:

DataTable dt = CreateDataTableInSomeWay();

List<DataRow> list = new List<DataRow>(); 
foreach (DataRow dr in dt.Rows)
{
    list.Add(dr);
}

Gibt es einen besseren / magischen Weg?

Iain Holder
quelle
2
Was versuchen Sie mit einer Liste zu erreichen, die Sie mit Ihrer DataRowCollection nicht tun können?
Jason Kealey
Meins ist spät, aber die Hoffnung wird nützlich sein. Arbeitslösung .. stackoverflow.com/a/58607820/9048996
Thameem

Antworten:

275

Wenn Sie .NET 3.5 verwenden, können Sie DataTableExtensions.AsEnumerable(eine Erweiterungsmethode) verwenden. Wenn Sie wirklich eine benötigen , können Sie List<DataRow>statt nur IEnumerable<DataRow>Folgendes aufrufen Enumerable.ToList:

IEnumerable<DataRow> sequence = dt.AsEnumerable();

oder

using System.Linq;
...
List<DataRow> list = dt.AsEnumerable().ToList();
Jon Skeet
quelle
wie man dies listin json umwandelt .
ACP
6
@ Pandiya: Es gibt verschiedene Möglichkeiten, Daten in .NET in JSON zu konvertieren. Persönlich habe ich immer die JSON.NET-Bibliothek verwendet, aber es gibt auch andere Ansätze.
Jon Skeet
1
@ Jon Skeet: Ich möchte den Wert in DataRow erhalten. Gibt es eine Methode? Anstatt wie eine Liste zu werden.ItemArray [0].
Ramesh Durai
@ Jon, FYI: dt.AsEnumerable (). ToList () 'System.Data.EnumerableRowCollection <System.Data.DataRow>' enthält keine Definition für 'ToList'
Pradip
66
List<Employee> emp = new List<Employee>();

//Maintaining DataTable on ViewState
//For Demo only

DataTable dt = ViewState["CurrentEmp"] as DataTable;

//read data from DataTable 
//using lamdaexpression


emp = (from DataRow row in dt.Rows

   select new Employee
   {
       _FirstName = row["FirstName"].ToString(),
       _LastName = row["Last_Name"].ToString()

   }).ToList();
Darshan Pandya
quelle
Der obige Code funktioniert möglicherweise nicht bcs. dt.Rows hat 'AsEnumerable' nicht implementiert. Dies kann wie folgt korrigiert werden: emp = (aus der DataRow-Zeile in dt.AsEnumerable () neuen Mitarbeiter auswählen {_FirstName = Zeile ["Vorname"]. ToString (), _LastName = Zeile ["Nachname"]. ToString ()}) .Auflisten();
Navin Pandit
37

Mit C # 3.0 und System.Data.DataSetExtensions.dll

List<DataRow> rows = table.Rows.Cast<DataRow>().ToList();
Marc Gravell
quelle
3
Dies hat die Leistung verbessert, indem nur ein foreach über einen Datenbereich um 50% der Zeit verwendet wurde.
Lloydom
33

Du könntest benutzen

List<DataRow> list = new List<DataRow>(dt.Select());

dt.Select()gibt alle Zeilen in Ihrer Tabelle als Array von Datenzeilen zurück, und der ListKonstruktor akzeptiert dieses Array von Objekten als Argument, mit dem Ihre Liste zunächst gefüllt werden soll.

Kibbee
quelle
Select () benötigt keine Parameter. Die parameterlose Überladung würde alle Zeilen zurückgeben.
Kon
Vielen Dank, meine Antwort an Ihren Vorschlag anzupassen
Kibbee
15

Sie können eine Erweiterungsfunktion erstellen als:

public static List<T> ToListof<T>(this DataTable dt)
{
    const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
    var columnNames = dt.Columns.Cast<DataColumn>()
        .Select(c => c.ColumnName)
        .ToList();
    var objectProperties = typeof(T).GetProperties(flags);
    var targetList = dt.AsEnumerable().Select(dataRow =>
    {
        var instanceOfT = Activator.CreateInstance<T>();

        foreach (var properties in objectProperties.Where(properties => columnNames.Contains(properties.Name) && dataRow[properties.Name] != DBNull.Value))
        {
            properties.SetValue(instanceOfT, dataRow[properties.Name], null);
        }
        return instanceOfT;
    }).ToList();

    return targetList;
}


var output = yourDataInstance.ToListof<targetModelType>();
Rahul Garg
quelle
Funktioniert nicht - siehe dotnetfiddle.net/I22r2c Es sollte auch beachtet werden, dass die Verwendung von Reflection langsam ist und in leistungskritischem Code nicht empfohlen wird.
Almenon
Sie müssen Datentypinformationen für Spalten hinzufügen. DataTable dt = new DataTable (); dt.Columns.Add ("id", typeof (Int32)); dt.Columns.Add ("name", typeof (String)); dt.Columns.Add ("foo", typeof (DateTime)); für (int i = 0; i <= 1000; i ++) {dt.Rows.Add (i, "foo", DateTime.Now);}
Rahul Garg
Funktioniert jetzt. Vielen Dank.
Almenon
14

Wenn Sie nur eine Liste von Werten aus dem Feld "ID" int zurückgeben möchten, können Sie ...

List<int> ids = (from row in dt.AsEnumerable() select Convert.ToInt32(row["ID"])).ToList();
Stuart
quelle
12

Ich habe den Code aus dieser Antwort ( https://stackoverflow.com/a/24588210/4489664 ) geändert, da bei nullbaren Typen eine Ausnahme zurückgegeben wird

public static List<T> DataTableToList<T>(this DataTable table) where T: new()
{
    List<T> list = new List<T>();
    var typeProperties = typeof(T).GetProperties().Select(propertyInfo => new
        {
            PropertyInfo = propertyInfo,
            Type = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType
        }).ToList();

    foreach (var row in table.Rows.Cast<DataRow>())
    {
        T obj = new T();
        foreach (var typeProperty in typeProperties)
        {
            object value = row[typeProperty.PropertyInfo.Name];
            object safeValue = value == null || DBNull.Value.Equals(value)
                ? null
                : Convert.ChangeType(value, typeProperty.Type);

            typeProperty.PropertyInfo.SetValue(obj, safeValue, null);
        }
        list.Add(obj);
    }
    return list;
}
Bondaryuk Vladimir
quelle
Ich habe die Klasse entfernt, weil sie auch mit struct funktionieren kann.
Mickey Perlstein
Das funktioniert ziemlich gut, gute Arbeit. Wenn jemand mit dem Code herumspielen
Almenon
@Almenon Ich habe kleine Modifikation hinzugefügt, es sollte ein bisschen Leistung steigern
Bondaryuk Vladimir
11
using System.Data;


var myEnumerable = myDataTable.AsEnumerable();

List<MyClass> myClassList =
    (from item in myEnumerable
     select new MyClass{
         MyClassProperty1 = item.Field<string>("DataTableColumnName1"),
         MyClassProperty2 = item.Field<string>("DataTableColumnName2")
    }).ToList();
Morteza
quelle
Brillant! Du hast meinen Tag gerettet
Anynomous Khan vor
6

Mit 3.5 können Sie es wieder wie folgt machen:

dt.Select().ToList()

BRGDS

Guilherme Duarte
quelle
4

Hier ist eine DataTable-Erweiterungsmethode, die eine DataTable in eine generische Liste konvertiert.

https://gist.github.com/gaui/a0a615029f1327296cf8

Verwendung:

List<Employee> emp = dtTable.DataTableToList<Employee>();
Gaui
quelle
4

Ein "magischerer" Weg, und .NET 3.5 wird nicht benötigt.

Wenn Sie beispielsweise DBDatatableeine einzelne Spalte mit Guids (eindeutige Kennung in SQL) zurückgeben, können Sie Folgendes verwenden:

Dim gList As New List(Of Guid)
gList.AddRange(DirectCast(DBDataTable.Select(), IEnumerable(Of Guid)))
Barney
quelle
4
// this is better suited for expensive object creation/initialization
IEnumerable<Employee> ParseEmployeeTable(DataTable dtEmployees)
{
    var employees = new ConcurrentBag<Employee>();

    Parallel.ForEach(dtEmployees.AsEnumerable(), (dr) =>
    {
        employees.Add(new Employee() 
        {
            _FirstName = dr["FirstName"].ToString(),
            _LastName = dr["Last_Name"].ToString()
        });
    });

    return employees;
}
Nathan
quelle
3

DataTable.Select() gibt die Zeilen nicht in der Reihenfolge an, in der sie in der Datentabelle vorhanden waren.

Wenn die Reihenfolge wichtig ist, ist es meiner Meinung nach der richtige Weg, die Datenreihen-Sammlung zu durchlaufen und eine Liste zu erstellen, oder Sie könnten auch eine Überladung von verwenden DataTable.Select(string filterexpression, string sort) .

Diese Überlastung behandelt jedoch möglicherweise nicht alle von SQL bereitgestellten Bestellungen (z. B. Reihenfolge nach Fall ...).

Benutzer129206
quelle
3
DataTable dt;   // datatable should contains datacolumns with Id,Name

List<Employee> employeeList=new List<Employee>();  // Employee should contain  EmployeeId, EmployeeName as properties

foreach (DataRow dr in dt.Rows)
{
    employeeList.Add(new Employee{EmployeeId=dr.Id,EmplooyeeName=dr.Name});
}
syed ali abbas
quelle
1

Verwenden Sie den System.DataNamespace, dann erhalten Sie .AsEnumerable().

Rajashekar
quelle
1
        /* This is a generic method that will convert any type of DataTable to a List 
         * 
         * 
         * Example :    List< Student > studentDetails = new List< Student >();  
         *              studentDetails = ConvertDataTable< Student >(dt);  
         *
         * Warning : In this case the DataTable column's name and class property name
         *           should be the same otherwise this function will not work properly
         */

Das Folgende sind die beiden Funktionen, in denen, wenn wir eine DataTable und eine benutzerdefinierte Klasse übergeben. Anschließend wird die Liste dieser Klasse mit den DataTable-Daten zurückgegeben.

        public static List<T> ConvertDataTable<T>(DataTable dt)
        {
            List<T> data = new List<T>();
            foreach (DataRow row in dt.Rows)
            {
                T item = GetItem<T>(row);
                data.Add(item);
            }
            return data;
        }


        private static T GetItem<T>(DataRow dr)
        {
            Type temp = typeof(T);
            T obj = Activator.CreateInstance<T>();

            foreach (DataColumn column in dr.Table.Columns)
            {
                foreach (PropertyInfo pro in temp.GetProperties())
                {
                   //in case you have a enum/GUID datatype in your model
                   //We will check field's dataType, and convert the value in it.
                    if (pro.Name == column.ColumnName){                
                    try
                    {
                        var convertedValue = GetValueByDataType(pro.PropertyType, dr[column.ColumnName]);
                        pro.SetValue(obj, convertedValue, null);
                    }
                    catch (Exception e)
                    {         
                       //ex handle code                   
                        throw;
                    }
                        //pro.SetValue(obj, dr[column.ColumnName], null);
                }
                    else
                        continue;
                }
            }
            return obj;
        }

Diese Methode überprüft den Datentyp des Felds und konvertiert den Wert von dataTable in diesen Datentyp.

    private static object GetValueByDataType(Type propertyType, object o)
    {
        if (o.ToString() == "null")
        {
            return null;
        }
        if (propertyType == (typeof(Guid)) || propertyType == typeof(Guid?))
        {
            return Guid.Parse(o.ToString());
        }
        else if (propertyType == typeof(int) || propertyType.IsEnum) 
        {
            return Convert.ToInt32(o);
        }
        else if (propertyType == typeof(decimal) )
        {
            return Convert.ToDecimal(o);
        }
        else if (propertyType == typeof(long))
        {
            return Convert.ToInt64(o);
        }
        else if (propertyType == typeof(bool) || propertyType == typeof(bool?))
        {
            return Convert.ToBoolean(o);
        }
        else if (propertyType == typeof(DateTime) || propertyType == typeof(DateTime?))
        {
            return Convert.ToDateTime(o);
        }
        return o.ToString();
    }

Verwenden Sie die folgende Syntax, um die vorhergehende Methode aufzurufen:

List< Student > studentDetails = new List< Student >();  
studentDetails = ConvertDataTable< Student >(dt); 

Ändern Sie den Namen der Schülerklasse und den dt-Wert entsprechend Ihren Anforderungen. In diesem Fall sollten der Name der DataTable-Spalte und der Name der Klasseneigenschaft identisch sein, da diese Funktion sonst nicht ordnungsgemäß funktioniert.

Saurin
quelle
1
Danke für deine Antwort. Es wäre großartig, wenn Sie Ihrem Code auch eine kurze Erklärung und einige Kommentare hinzufügen würden. Dies hilft den Menschen, Ihre Antwort besser zu verstehen.
Andre Hofmeister
0

Dies hat bei mir funktioniert: Benötigen Sie mindestens .Net Framework 3.5. Der folgende Code zeigt DataRow an. Generic.IEnumerable, comboBox1 wurde zur besseren Veranschaulichung verwendet.

using System.Linq;

DataTable dt = new DataTable();            
dt = myClass.myMethod();                 
List<object> list = (from row in dt.AsEnumerable() select (row["name"])).ToList();
comboBox1.DataSource = list;
Levi
quelle
0

Ausgabe

public class ModelUser
{
    #region Model

    private string _username;
    private string _userpassword;
    private string _useremail;
    private int _userid;

    /// <summary>
    /// 
    /// </summary>
    public int userid
    {
        set { _userid = value; }
        get { return _userid; }
    }


    /// <summary>
    /// 
    /// </summary>

    public string username
    {
        set { _username = value; }
        get { return _username; }
    }

    /// <summary>
    /// 
    /// </summary>
    public string useremail
    {
        set { _useremail = value; }
        get { return _useremail; }
    }

    /// <summary>
    /// 
    /// </summary>
    public string userpassword
    {
        set { _userpassword = value; }
        get { return _userpassword; }
    }
    #endregion Model
}

public List<ModelUser> DataTableToList(DataTable dt)
{
    List<ModelUser> modelList = new List<ModelUser>();
    int rowsCount = dt.Rows.Count;
    if (rowsCount > 0)
    {
        ModelUser model;
        for (int n = 0; n < rowsCount; n++)
        {
            model = new ModelUser();

            model.userid = (int)dt.Rows[n]["userid"];
            model.username = dt.Rows[n]["username"].ToString();
            model.useremail = dt.Rows[n]["useremail"].ToString();
            model.userpassword = dt.Rows[n]["userpassword"].ToString();

            modelList.Add(model);
        }
    }
    return modelList;
}

static DataTable GetTable()
{
    // Here we create a DataTable with four columns.
    DataTable table = new DataTable();
    table.Columns.Add("userid", typeof(int));
    table.Columns.Add("username", typeof(string));
    table.Columns.Add("useremail", typeof(string));
    table.Columns.Add("userpassword", typeof(string));

    // Here we add five DataRows.
    table.Rows.Add(25, "Jame", "[email protected]", DateTime.Now.ToString());
    table.Rows.Add(50, "luci", "[email protected]", DateTime.Now.ToString());
    table.Rows.Add(10, "Andrey", "[email protected]", DateTime.Now.ToString());
    table.Rows.Add(21, "Michael", "[email protected]", DateTime.Now.ToString());
    table.Rows.Add(100, "Steven", "[email protected]", DateTime.Now.ToString());
    return table;
}

protected void Page_Load(object sender, EventArgs e)
{
    List<ModelUser> userList = new List<ModelUser>();

    DataTable dt = GetTable();

    userList = DataTableToList(dt);

    gv.DataSource = userList;
    gv.DataBind();
}[enter image description here][1]

</asp:GridView>
</div>
mrtwin
quelle
0

Wir können eine generische Methode verwenden zur Umwandlung DataTablezu Listanstatt manuell eine Umwandlung DataTablezu List.

Hinweis: DataTable's ColumnNameund Type' s PropertyNamesollten gleich sein.

Rufen Sie die folgende Methode auf:

long result = Utilities.ConvertTo<Student>(dt ,out listStudent);

// Generic Method
public class Utilities
{
    public static long ConvertTo<T>(DataTable table, out List<T> entity)
    {
        long returnCode = -1;
        entity = null;

        if (table == null)
        {
            return -1;
        }

        try
        {
            entity = ConvertTo<T>(table.Rows);
            returnCode = 0;
        }

        catch (Exception ex)
        {
            returnCode = 1000;
        }

        return returnCode;
    }

    static List<T> ConvertTo<T>(DataRowCollection rows)
    {
        List<T> list = null;
        if (rows != null)
        {
            list = new List<T>();

            foreach (DataRow row in rows)
            {
                T item = CreateItem<T>(row);
                list.Add(item);
            }
        }

        return list;
    }

    static T CreateItem<T>(DataRow row)
    {
        string str = string.Empty;
        string strObj = string.Empty;

        T obj = default(T);

        if (row != null)
        {
            obj = Activator.CreateInstance<T>();
            strObj = obj.ToString();
            NameValueCollection objDictionary = new NameValueCollection();

            foreach (DataColumn column in row.Table.Columns)
            {
                PropertyInfo prop = obj.GetType().GetProperty(column.ColumnName);

                if (prop != null)
                {
                    str = column.ColumnName;

                    try
                    {
                        objDictionary.Add(str, row[str].ToString());
                        object value = row[column.ColumnName];
                        Type vType = obj.GetType();

                        if (value == DBNull.Value)
                        {
                            if (vType == typeof(int) || vType == typeof(Int16)
                                                     || vType == typeof(Int32)
                                                     || vType == typeof(Int64)
                                                     || vType == typeof(decimal)
                                                     || vType == typeof(float)
                                                     || vType == typeof(double))
                            {
                                value = 0;
                            }

                            else if (vType == typeof(bool))
                            {
                                value = false;
                            }

                            else if (vType == typeof(DateTime))
                            {
                                value = DateTime.MaxValue;
                            }

                            else
                            {
                                value = null;
                            }

                            prop.SetValue(obj, value, null);
                        }

                        else
                        {
                            prop.SetValue(obj, value, null);
                        }
                    }

                    catch(Exception ex)
                    {

                    }
                }
            }

            PropertyInfo ActionProp = obj.GetType().GetProperty("ActionTemplateValue");

            if (ActionProp != null)
            {
                object ActionValue = objDictionary;
                ActionProp.SetValue(obj, ActionValue, null);
            }
        }

        return obj;
    }
}
Jayaprakash
quelle
0

Sie können eine solche generische Methode für Daten verwenden, die auf generische Listen datiert werden können

public static List<T> DataTableToList<T>(this DataTable table) where T : class, new()
{
    try
    {
        List<T> list = new List<T>();

        foreach (var row in table.AsEnumerable())
        {
            T obj = new T();

            foreach (var prop in obj.GetType().GetProperties())
            {
                try
                {
                    PropertyInfo propertyInfo = obj.GetType().GetProperty(prop.Name);
                    if (propertyInfo.PropertyType.IsEnum)
                    {
                        propertyInfo.SetValue(obj, Enum.Parse(propertyInfo.PropertyType, row[prop.Name].ToString()));
                    }
                    else
                    {
                        propertyInfo.SetValue(obj, Convert.ChangeType(row[prop.Name], propertyInfo.PropertyType), null);
                    }                          
                }
                catch
                {
                    continue;
                }
            }

            list.Add(obj);
        }

        return list;
    }
    catch
    {
        return null;
    }
}
Ömer Ceylan
quelle
0

Umstellung DataTableauf GenericDictionary

public static Dictionary<object,IList<dynamic>> DataTable2Dictionary(DataTable dt)
{
    Dictionary<object, IList<dynamic>> dict = new Dictionary<dynamic, IList<dynamic>>();

    foreach(DataColumn column in dt.Columns)
    {
        IList<dynamic> ts = dt.AsEnumerable()
                              .Select(r => r.Field<dynamic>(column.ToString()))
                              .ToList();
        dict.Add(column, ts);
    }
    return dict;
}
Anil
quelle
0

Verwenden Sie die Erweiterung:

public static class Extensions
{
    #region Convert Datatable To List
    public static IList<T> ToList<T>(this DataTable table) where T : new()
    {
        IList<PropertyInfo> properties = typeof(T).GetProperties().ToList();
        IList<T> result = new List<T>();

        foreach (var row in table.Rows)
        {
            var item = CreateItemFromRow<T>((DataRow)row, properties);
            result.Add(item);
        }
        return result;
    }
    private static T CreateItemFromRow<T>(DataRow row, IList<PropertyInfo> properties) where T : new()
    {
        T item = new T();
        foreach (var property in properties)
        {
            property.SetValue(item, row[property.Name], null);
        }
        return item;
    }
    #endregion
}
mohamed mostafa
quelle
0

So weisen Sie die DataTable-Zeilen der generischen Klassenliste zu

  List<Candidate> temp = new List<Candidate>();//List that holds the Candidate Class,
    //Note:The Candidate class contains RollNo,Name and Department
    //tb is DataTable
    temp = (from DataRow dr in tb.Rows
                        select new Candidate()
                        {
                            RollNO = Convert.ToInt32(dr["RollNO"]),
                            Name = dr["Name"].ToString(),
                            Department = dr["Department"].ToString(),

                        }).ToList();
Maghalakshmi Saravana
quelle
0

Die einfachste Möglichkeit, die DataTable in die generische Klassenliste zu konvertieren

mit Newtonsoft.Json;

var json = JsonConvert.SerializeObject(dataTable);
var model = JsonConvert.DeserializeObject<List<ClassName>>(json);
Maghalakshmi Saravana
quelle
0

Sie können die folgenden zwei allgemeinen Funktionen verwenden

private static List<T> ConvertDataTable<T>(DataTable dt)
    {
        List<T> data = new List<T>();
        foreach (DataRow row in dt.Rows)
        {
            T item = GetItem<T>(row);
            data.Add(item);
        }
        return data;
    }
    private static T GetItem<T>(DataRow dr)
    {

        Type temp = typeof(T);
        T obj = Activator.CreateInstance<T>();

        foreach (DataColumn column in dr.Table.Columns)
        {
            foreach (PropertyInfo pro in temp.GetProperties())
            {
                if (pro.Name == column.ColumnName)
                    pro.SetValue(obj, dr[column.ColumnName].ToString(), null);
                else
                    continue;
            }
        }
        return obj;
    }

und verwenden Sie es wie folgt

List<StudentScanExamsDTO> studentDetails = ConvertDataTable<StudentScanExamsDTO>(dt);
Hosam Hemaily
quelle
0
lPerson = dt.AsEnumerable().Select(s => new Person()
        {
            Name = s.Field<string>("Name"),
            SurName = s.Field<string>("SurName"),
            Age = s.Field<int>("Age"),
            InsertDate = s.Field<DateTime>("InsertDate")
        }).ToList();

Link zum funktionierenden DotNetFiddle-Beispiel

using System;
using System.Collections.Generic;   
using System.Data;
using System.Linq;
using System.Data.DataSetExtensions;

public static void Main()
{
    DataTable dt = new DataTable();
    dt.Columns.Add("Name", typeof(string));
    dt.Columns.Add("SurName", typeof(string));
    dt.Columns.Add("Age", typeof(int));
    dt.Columns.Add("InsertDate", typeof(DateTime));

    var row1= dt.NewRow();
    row1["Name"] = "Adam";
    row1["SurName"] = "Adam";
    row1["Age"] = 20;
    row1["InsertDate"] = new DateTime(2020, 1, 1);
    dt.Rows.Add(row1);

    var row2 = dt.NewRow();
    row2["Name"] = "John";
    row2["SurName"] = "Smith";
    row2["Age"] = 25;
    row2["InsertDate"] = new DateTime(2020, 3, 12);
    dt.Rows.Add(row2);

    var row3 = dt.NewRow();
    row3["Name"] = "Jack";
    row3["SurName"] = "Strong";
    row3["Age"] = 32;
    row3["InsertDate"] = new DateTime(2020, 5, 20);
    dt.Rows.Add(row3);

    List<Person> lPerson = new List<Person>();
    lPerson = dt.AsEnumerable().Select(s => new Person()
    {
        Name = s.Field<string>("Name"),
        SurName = s.Field<string>("SurName"),
        Age = s.Field<int>("Age"),
        InsertDate = s.Field<DateTime>("InsertDate")
    }).ToList();

    foreach(Person pers in lPerson)
    {
        Console.WriteLine("{0} {1} {2} {3}", pers.Name, pers.SurName, pers.Age, pers.InsertDate);
    }
}   

public class Person
{
    public string Name { get; set; }
    public string SurName { get; set; }
    public int Age { get; set; }
    public DateTime InsertDate { get; set; }
}

}}

Herr R.
quelle