Convert DataTable to Generic List в C #

Предоставить использование / выбрать для одной таблицы

Если вы предоставляете только CONNECT для базы данных, пользователь может подключиться, но не имеет других привилегий. Вы должны предоставить USAGE для пространств имен (схем) и SELECT для таблиц и представлений по отдельности, например:

GRANT CONNECT ON DATABASE mydb TO xxx;
-- This assumes you're actually connected to mydb..
GRANT USAGE ON SCHEMA public TO xxx;
GRANT SELECT ON mytable TO xxx;

Несколько таблиц / представлений (PostgreSQL 9.0 +)

В последних версиях PostgreSQL Вы можете предоставить разрешения для всех таблиц / представлений / и т. д. в схеме, используя одну команду, вместо того, чтобы вводить их по одному:

GRANT SELECT ON ALL TABLES IN SCHEMA public TO xxx;

Это влияет только на таблицы, которые уже были созданы. Более эффективно, вы можете автоматически иметь роли по умолчанию, назначенные новым объектам в будущем:

ALTER DEFAULT PRIVILEGES IN SCHEMA public
   GRANT SELECT ON TABLES TO xxx;

Обратите внимание, что по умолчанию это повлияет только на объекты (таблицы), созданные пользователем, который выдал это команда: хотя она также может быть установлена ​​для любой роли, членом которой является выдающий пользователь. Однако вы не выбираете привилегии по умолчанию для всех ролей, в которых вы участвуете, при создании новых объектов ... так что все еще есть некоторые недоработки. Если вы принимаете подход, согласно которому база данных играет роль-владелец, а изменения схемы выполняются в качестве этой роли-владельца, вам следует назначить привилегии по умолчанию для этой роли-владельца. ИМХО, все это немного сбивает с толку, и вам, возможно, придется поэкспериментировать, чтобы придумать функциональный рабочий процесс.

Несколько таблиц / представлений (версии PostgreSQL до 9.0)

Чтобы избежать ошибок при длительных многостоловых изменениях, рекомендуется использовать следующий «автоматический» процесс для генерации требуемого GRANT SELECT для каждого table / view:

SELECT 'GRANT SELECT ON ' || relname || ' TO xxx;'
FROM pg_class JOIN pg_namespace ON pg_namespace.oid = pg_class.relnamespace
WHERE nspname = 'public' AND relkind IN ('r', 'v', 'S');

Это должно вывести соответствующие команды GRANT в GRANT SELECT для всех открытых таблиц, представлений и последовательностей для копирования-n-paste. Естественно, это будет применяться только к таблицам, которые уже были созданы.

26
задан Cœur 10 July 2018 в 14:14
поделиться

3 ответа

Я думаю, что все решения можно улучшить и сделать метод более общим, если вы используете некоторые соглашения и рефлексию. Допустим, вы называете свои столбцы в таблице данных тем же именем, что и свойства в вашем объекте, тогда вы можете написать что-то, что будет проверять все ваши свойства вашего объекта, а затем искать этот столбец в таблице данных для сопоставления значения.

Я сделал противоположное, то есть ... от IList до datatable, и код, который я написал, можно увидеть по адресу: http://blog.tomasjansson.com/convert-datatable-to- generic-list-extension /

Не должно быть так сложно идти другим путем, и должно быть так сложно перегружать функции, чтобы вы могли предоставить информацию о том, какие свойства вы хотите включить или исключить.

РЕДАКТИРОВАТЬ: Таким образом, код, чтобы заставить его работать:

public static class DataTableExtensions
{
    private static Dictionary<Type,IList<PropertyInfo>> typeDictionary = new Dictionary<Type, IList<PropertyInfo>>();
    public static IList<PropertyInfo> GetPropertiesForType<T>()
    {
        var type = typeof(T);
        if(!typeDictionary.ContainsKey(typeof(T)))
        {
            typeDictionary.Add(type, type.GetProperties().ToList());
        }
        return typeDictionary[type];
    }

    public static IList<T> ToList<T>(this DataTable table) where T : new()
    {
        IList<PropertyInfo> properties = GetPropertiesForType<T>();
        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;
    }

}

Если у вас есть DataTable, вы можете просто написать yourTable.ToList<YourType>() и он создаст список для вас. Если у вас более сложный тип с вложенными объектами, вам нужно обновить код. Одно из предложений - просто перегрузить метод ToList, чтобы принять params string[] excludeProperties, который содержит все ваши свойства, которые не должны отображаться. Конечно, вы можете добавить проверку нуля в цикл foreach метода CreateItemForRow.

ОБНОВЛЕНИЕ: Добавлен статический словарь для сохранения результата от операции отражения, чтобы сделать его немного быстрее. Я не скомпилировал код, но он должен работать :).

12
ответ дан 28 November 2019 в 06:37
поделиться

Опаздывает, но это может быть полезно. Можно вызвать с помощью:

table.Map (); или вызвать Func для фильтрации значений.

Вы даже можете изменить имя отображения между свойством type и заголовком DataColumn, установив атрибуты для свойства.

[AttributeUsage(AttributeTargets.Property)]
    public class SimppleMapperAttribute: Attribute
    {
        public string HeaderName { get; set; }
    }


     public static class SimpleMapper
{
    #region properties
    public static bool UseDeferredExecution { get; set; } = true;
    #endregion

#region public_interface  


    public static IEnumerable<T> MapWhere<T>(this DataTable table, Func<T, bool> sortExpression) where T:new()
    {
        var result = table.Select().Select(row => ConvertRow<T>(row, table.Columns, typeof(T).GetProperties())).Where((t)=>sortExpression(t));
        return UseDeferredExecution ? result : result.ToArray();
    }
    public static IEnumerable<T> Map<T>(this DataTable table) where T : new()
    {
        var result = table.Select().Select(row => ConvertRow<T>(row, table.Columns, typeof(T).GetProperties()));
        return UseDeferredExecution ? result : result.ToArray();
    }
    #endregion

#region implementation_details
    private static T ConvertRow<T>(DataRow row, DataColumnCollection columns, System.Reflection.PropertyInfo[] p_info) where T : new()
    {
        var instance = new T();
        foreach (var info in p_info)
        {
            if (columns.Contains(GetMappingName(info))) SetProperty(row, instance, info);             
        }
        return instance;
    }

    private static void SetProperty<T>(DataRow row, T instance, System.Reflection.PropertyInfo info) where T : new()
    {
        string mp_name = GetMappingName(info);
        object value = row[mp_name];
        info.SetValue(instance, value);
    }

    private static string GetMappingName(System.Reflection.PropertyInfo info)
    {
        SimppleMapperAttribute attribute = info.GetCustomAttributes(typeof(SimppleMapperAttribute),true).Select((o) => o as SimppleMapperAttribute).FirstOrDefault();
        return attribute == null ? info.Name : attribute.HeaderName;
    }
#endregion
}
0
ответ дан 28 November 2019 в 06:37
поделиться

Просто небольшое упрощение. Я не использую ItemArray:

List<Person> list = tbl.AsEnumerable().Select(x => new Person
                    {
                        Id = (Int32) (x["Id"]),
                        Name = (string) (x["Name"] ?? ""),
                        LastName = (string) (x["LastName"] ?? "")
                    }).ToList();
8
ответ дан 28 November 2019 в 06:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: