LINQ-подобный или SQL-подобный DSL для конечных пользователей для запуска запросов для выбора (не изменения) данных? - PullRequest
1 голос
/ 16 марта 2010

Для утилиты, над которой я работаю, клиент хотел бы иметь возможность генерировать графические отчеты по собранным данным. Я уже могу сгенерировать пару готовых графиков (используя ZedGraph, очень приятная библиотека); однако утилита была бы намного более гибкой, если бы графики были более программируемыми или настраиваемыми конечным пользователем.

TLDR версия

Я хочу, чтобы пользователи могли использовать что-то вроде SQL для безопасного извлечения и выбора данных из списка объектов, которые я предоставляю и могу описать. Какие бесплатные инструменты или библиотеки помогут мне в этом?

Полная версия

Я задумался об использовании IronPython, IronRuby и LuaInterface, но, честно говоря, все они немного подавлены тем, что я хочу сделать. Мои классы довольно просты:

class Person:
    string Name;
    int HeightInCm;
    DateTime BirthDate;
    Weight[] WeighIns;

class Weight:
    int WeightInKg;
    DateTime Date;
    Person Owner;

(точные классы были изменены, чтобы защитить невинных).

Чтобы получить данные для графика, пользователь сам выберет, является ли он гистограммой, точечной диаграммой и т. Д., А затем для фактического получения данных я хотел бы просто получить какой-то список от пользователя. ввод чего-то SQL-кода в соответствии с

SELECT Name, AVG(WeighIns) FROM People
SELECT WeightInKg, Owner.HeightInCm FROM Weights

И в качестве бонуса было бы неплохо, если бы вы могли на самом деле выполнять операции:

SELECT WeightInKg, (Date - Owner.BirthDate) AS Age FROM Weights

DSL никоим образом не должен соответствовать SQL; он даже не должен напоминать SQL, но я не могу придумать более эффективный описательный язык для этой задачи.

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

var personRequest = Request<Person>();
personRequest.Item("Name", (p => p.Name));
personRequest.Item("HeightInCm", (p => p.HeightInCm));
personRequest.Item("HeightInInches", (p => p.HeightInCm * CM_TO_INCHES));
// ...
var weightRequest = Request<Weight>();
weightRequest.Item("Owner", (w => w.Owner), personRequest); // Indicate a chain to personRequest
// ...
var people = Table<Person>("People", GetPeopleFromDatabase());
var weights = Table<Weight>("Weights", GetWeightsFromDatabase());
// ...
TryRunQuery(userInputQuery);

LINQ - это , поэтому близко к тому, что я хочу сделать, но AFAIK, нет никакого способа изолировать его. Я не хочу предоставлять какой-либо ненужный функционал конечному пользователю; То есть я не хочу, чтобы пользователь мог отправлять и обрабатывать:

from p in people select (p => { System.IO.File.Delete("C:\\something\\important"); return p.Name })

Так кто-нибудь знает о каких-либо бесплатных библиотеках .NET, которые позволяют что-то вроде того, что я описал выше? Или есть какой-нибудь способ песочницы LINQ? cs-script тоже близко, но пока не предлагает песочницу. Я бы не хотел выставлять интерфейс NHibernate, так как пользователь должен иметь доступ к данным только для чтения на данном этапе использования.

Я использую C # 3.5, и предпочтение отдается чистым решениям .NET.

Суть в том, что я действительно стараюсь не писать свой собственный синтаксический анализатор для подмножества SQL, которое применимо только к этому единственному проекту.

Ответы [ 3 ]

0 голосов
/ 16 марта 2010

Может быть, вам пригодятся выражения. Вы можете предоставить простые места для входа: a) что выбрать - пользователь должен вводить только выражение _ возможно член и арифметические выражения - это подклассы класса выражений б) как фильтровать вещи = опять ожидаются только выражения в) заказ г) присоединиться?

Выражения не позволяют Вам делать File.Delete, потому что Вы работаете только с точными объектами домена (которые, вероятно, не имеют этой функции). Единственное, что Вам нужно проверить, это то, относятся ли параметры указанных выражений к типам Вашего домена. и Возвращаемые типы упомянутых выражений имеют типы доменов (или универсальные типы в случае IEnumerable <> или IQuerable <>

это может оказаться полезным
И.Е. выражения не позволяют писать многострочные операторы.

Тогда вы строите свою цепочку методов в коде. и вуаля. Там приходят данные

0 голосов
/ 18 марта 2010

В итоге я использовал немного другой подход. Вместо того, чтобы позволять пользователям выбирать произвольные поля и создавать произвольные графики, я все еще представляю постоянные графики, но я использую Flee , чтобы позволить пользователю точно отфильтровать, какие данные используются в источнике графика. Это хорошо работает, потому что в итоге я сделал набор сопоставлений из имен переменных в «средства доступа», а затем использовал эти сопоставления для введения переменных в фильтры, введенные пользователем. В итоге получилось что-то вроде:

List<Mapping<Person>> mappings;
// ...
mappings.Add(new Mapping("Weight", p => p.Weight, "The person's weight (in pounds)"));
// ...
foreach (var m in mappings)
{
    context.Variables[m.Name] = m.Accessor(p);
}
// ...

И вы даже можете дать контексту выражения «владелец» (например, Ruby's instance_eval, где контекст выполняется с оценкой указанного объекта как this); тогда пользователь может даже ввести фильтр, например Weight > InputNum("The minimum weight to see"), и тогда ему будет предложено при запуске этого фильтра, потому что я определил метод InputNum в классе-владельце.

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

0 голосов
/ 16 марта 2010

Существует способ изолированной среды LINQ или даже C #: A изолированная область приложения appdomain . Я бы порекомендовал вам принять и скомпилировать LINQ в заблокированном домене.

Что касается NHibernate, возможно, вы можете передать объекты в домен, не раскрывая NHibernate вообще (я не знаю, как работает NHibernate). Если это невозможно, возможно, подключение к базе данных, используемой в изолированной программной среде, может быть зарегистрировано как пользователь, которому предоставлены только разрешения SELECT.

...