ооо большая тема :)
Самый простой способ запроса с помощью объекта DacFxStronglyTypedModel, который доступен:
https://github.com/Microsoft/DACExtensions
Это немного странно, что это образец, который вы строите и то это дает вам легкий доступ для запроса DacFx:
https://github.com/Microsoft/DACExtensions/tree/master/DacFxStronglyTypedModel
Для того, чтобы получить сильно типизированных модель сделать:
var model = new TSqlTypedModel("dacpacPath");
Затем, когда вы запрашиваете его для всех видов (или любой другой), вы получите список типизированных объектов, которые много «здравомыслящим», чем DacFx.
интерфейс, который вы получите обратно для просмотров:
ISql120TSqlView (изменить номер версии на ваш номер версии) имеет IEnumerable столбцов:
IEnumerable<Microsoft.SqlServer.Dac.Extensions.Prototype.ISql120TSqlColumn> Columns { get; }
Интерфейс колонки затем IEnumerable из Datatypes:
IEnumerable<Microsoft.SqlServer.Dac.Extensions.Prototype.ISqlDataType> DataType { get; }
Я не получил оконный компьютер прямо сейчас, чтобы получить полную демоверсию, но этого должно быть достаточно, если вы не получите то, что вам нужно, добавьте комментарий, и я получу образец завтра (если никто еще не сделает это в то же время).
Чтобы получить список столбцов на вид сделать:
var views = model.GetObjects<TSqlView>(DacQueryScopes.UserDefined); foreach (var v in views) { Console.WriteLine(v.Columns.Count()); }
Это работает для меня с версией Дак DLL файлы 130.
Чтобы получить информацию о вычисляемых столбцах, вам необходимо просмотреть «ExpressionDependencies» в столбце (см. V.Columns), который является таким же, как и для таблиц.
EDIT
Так что я был с игрой, и есть некоторые вещи, которые вы просто не можете определить только во время выполнения, поэтому DacFx не смогут определить тип для тех, и только они, как я знаю, что на самом деле формирования набора записей и изучения того, что вы получите обратно, но есть некоторые вещи, которые мы можем сделать с вычисляемыми столбцами, если мы возьмем этот пример:
create table [dbo].[the_table] ( [Id] INT not null primary key, [StringCol] varchar(234) not null, [a] int, [b] decimal, [a_and_b] as [a] + [b] )
для колонн, Id, StringCol, а и b, когда мы используем строго типизированный dacfx, мы можем получить типы столбцов, выполнив следующее:
var tables = model.GetObjects(DacQueryScopes.UserDefined); foreach (var t in tables) { switch (c.ColumnType) { case ColumnType.Column: ShowType(c.DataType); break; } }
ShowType выглядит следующим образом:
`ничтожной ShowType (IEnumerable типов) { вар строитель = новый StringBuilder();
foreach (var type in types)
{
var t = new TSqlDataType(type.Element);
builder.Append($"{t.SqlDataType.ToString()} ");
}
Console.Write(builder);
}`
Что мы делаем, есть список типов данных для каждого столбца, это может быть просто INT или что-то подобное, но это список.
Теперь, потому что у нас есть вычисляемый столбец, а не только от типа данных (ов) мы имеем ссылку на нижележащие колонны, которые мы можем получить тип данных (ы) от:
void ShowDependencies(IEnumerable<ISqlModelElementReference> dependencies) { foreach (var dependency in dependencies) { if (dependency is TSqlColumnReference) { var column = new TSqlColumn(dependency.Element); Console.Write(column.Name + " "); ShowType(column.DataType); } } }
в знать, когда следует назвать эту версию:
`var tables = model.GetObjects (DacQueryScopes.Определяемые пользователем);
foreach (var t in tables)
{
Console.WriteLine($"table - {t.Name}");
foreach (var c in t.Columns)
{
Console.Write("\r\n" + c.Name.ToString() + " ");
switch (c.ColumnType)
{
case ColumnType.Column:
ShowType(c.DataType);
break;
case ColumnType.ComputedColumn:
Console.Write($"({c.Expression}) ");
ShowDependencies(c.ExpressionDependencies);
break;
`
для образца таблицы о мы получаем следующий результат:...
` таблицы - [DBO] [the_table]
[DBO] [the_table] [Id ] Int [dbo]. [The_table]. [StringCol] VarChar [dbo]. [The_table]. [A] Int [dbo]. [The_table]. [B] Десятичный [dbo]. [The_table]. [a_and_b] ([a] + [b]) [dbo]. [the_table]. [a] Int [dbo]. [the_table]. [b] Decima l view - [dbo]. [mutli_type] `
Нам нужно было бы решить, что это за тип, поскольку предположение sql будет делать неявное преобразование в качестве среды выполнения в десятичную, но во время компиляции я не думаю, что это известен (рад исправить здесь!)
Если затем принять вид в качестве примера:
create view the_view as select *, object_name(4) some_name, 123 as an_int from the_table
мы имеем столбцы из базовой таблицы, которые могут быть перечислены просто, но в имя_объект и 123 немного сложнее, используя тот же код выше, но для просмотров мы получаем:
[dbo].[the_view].[Id] [dbo].[the_table].[Id] Int [dbo].[the_view].[StringCol] [dbo].[the_table].[StringCol] VarChar [dbo].[the_view].[a] [dbo].[the_table].[a] Int [dbo].[the_view].[b] [dbo].[the_table].[b] Decimal [dbo].[the_view].[a_and_b] [dbo].[the_table].[a_and_b] [dbo].[the_view].[some_name] some_name = an_int = [dbo].[the_view].[an_int] some_name = an_int =
Так нет типа для вычисляемых столбцов плюс, чтобы добраться до значения для a_and_b мы должны были бы дополнительно перечислить еще раз, чтобы получить типы, которые мы имели выше.
На данный момент у вас есть представление со столбцами, которые указывают на функции/выражения, и это то, где начинает усложняться :), если вы возьмете пример выше, вы, вероятно, могли бы решить, какое имя object_name и определить это когда вы получаете представление, которое не является детерминированным ни по типу данных, ни по типу данных, что вы делаете?
Если мы возьмем:
create view mutli_type as select case datepart(day, getdate()) when 1 then 100 when 2 then 'hello' else getdate() end as multitype
в зависимости от дня мы получаем другой тип данных, возвращаемый - двойной Уч.
Если вам действительно нужно знать, что получилось, вы можете получить элементы выбора в представлении и использовать TSqlScript Dom для анализа их на части и попробовать и сделать вывод о каждом из них, я издевался над образцом, который находит getdate() в этом представлении, чтобы дать вам представление о том, что вам нужно сделать, но это не просто, и я даже не хочу рассматривать хранимые процедуры, в которых вы можете перейти в динамическом sql:
Полный образец:
`create table [dbo].[The_table] ( [Id] INT не нулевой первичный ключ, [StringCol] VARCHAR (234) не равно нулю, [а] Int, [Ь] десятичную, [a_and_b], как [а] + [Ь] ) пойти создать вид the_view в выберите *, object_name (4) некоторое_имя, 123, как an_int из the_table пойти создать вид mutli_type как выберите случай DATEPART (день, GetDate()) когда 1 затем 100 , когда 2 , затем 'hello' else GETDATE() конец, как многотипные идти
`
` с помощью системы; с использованием System.Collections.Generic; с использованием System.IO; с использованием System.Linq; с использованием System.Text; с использованием System.Threading.Tasks; с использованием Microsoft.SqlServer.Dac.Extensions.Prototype; с использованием Microsoft.SqlServer.Dac.Model; с использованием Microsoft.SqlServer.TransactSql.ScriptDom; , используя ColumnType = Microsoft.SqlServer.Dac.Model.ColumnType;
имен ConsoleApplication1 { класс Программа { статической силы ShowType (IEnumerable типов) { вар строитель = новый StringBuilder();
foreach (var type in types)
{
var t = new TSqlDataType(type.Element);
builder.Append($"{t.SqlDataType.ToString()} ");
}
Console.Write(builder);
}
static void ShowDependencies(IEnumerable<ISqlModelElementReference> dependencies)
{
foreach (var dependency in dependencies)
{
if (dependency is TSqlColumnReference)
{
var column = new TSqlColumn(dependency.Element);
Console.Write(column.Name + " ");
ShowType(column.DataType);
}
}
}
static void Main(string[] args)
{
var model = new TSqlTypedModel(@"path\Da.dacpac");
var views = model.GetObjects<TSqlView>(DacQueryScopes.UserDefined);
var tables = model.GetObjects<TSqlTable>(DacQueryScopes.UserDefined);
foreach (var t in tables)
{
Console.WriteLine($"table - {t.Name}");
foreach (var c in t.Columns)
{
Console.Write("\r\n" + c.Name.ToString() + " ");
switch (c.ColumnType)
{
case ColumnType.Column:
ShowType(c.DataType);
break;
case ColumnType.ComputedColumn:
Console.Write($"({c.Expression}) ");
ShowDependencies(c.ExpressionDependencies);
break;
case ColumnType.ColumnSet:
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
foreach (var v in views)
{
Console.WriteLine($"view - {v.Name}");
foreach (var c in v.Columns)
{
Console.Write("\r\n" + c.Name.ToString() + " ");
var needDomParse = false;
switch (c.ColumnType)
{
case ColumnType.Column:
ShowType(c.DataType);
ShowDependencies(c.ExpressionDependencies);
break;
case ColumnType.ComputedColumn:
ShowType(c.DataType);
ShowDependencies(c.ExpressionDependencies);
if (!c.DataType.Any() && !c.ExpressionDependencies.Any())
{
needDomParse = true;
}
break;
case ColumnType.ColumnSet:
break;
default:
throw new ArgumentOutOfRangeException();
}
if (needDomParse)
{
//ouch
var create = new CreateViewStatement();
var parser = new TSql130Parser(false);
IList<ParseError> errors;
var fragment = parser.Parse(new StringReader(v.GetScript()), out errors);
var selectVisitor = new SelectVisitor();
fragment.Accept(selectVisitor);
foreach (var s in selectVisitor.Selects)
{
var spec = s.QueryExpression as QuerySpecification;
foreach (var element in spec.SelectElements)
{
var select = element as SelectScalarExpression;
if (select != null)
{
Console.Write(select.ColumnName.Value + " = ");
var caseExpression = select.Expression as SimpleCaseExpression;
if (caseExpression != null)
{
var func = caseExpression.ElseExpression as FunctionCall;
Console.WriteLine(func.FunctionName.Value);
}
}
}
}
}
}
}
}
}
internal class SelectVisitor : TSqlConcreteFragmentVisitor
{
public List<SelectStatement> Selects = new List<SelectStatement>();
public override void Visit(SelectStatement node)
{
Selects.Add(node);
base.Visit(node);
}
}
}
`
Я надеюсь, что это помогает, я знаю, что это не просто сделать это, но мы надеемся, объясняет некоторые из проблем :)
Ed
I на самом деле смотрел прямо на исходный код для сильно типизированной модели ... если вы копаете немного, оказывается, что они используют точный метод для получения информации о типе (за исключением того, что они используют GetReferencedRelationsh ipInstances вместо GetReferenced, который я также пробовал). Я попробую это через минуту, но я убежден, что их код также не будет содержать информацию о типе данных. – user1935361
Я обновил свой вопрос выше, не купил :( – user1935361
Я добавил к ответу - если вы не получите его работу, можете ли вы дать образец t-sql, который вы пытаетесь выяснить, и я должен уметь дайте вам образец для этого –