LinqToSql DataContext с извлеченным интерфейсом не составляет SQL для функций - PullRequest
2 голосов
/ 07 января 2012

Я настроил тестовую базу данных и консольное приложение, чтобы подтвердить следующее:

Имеется база данных SQL со следующей функцией:

CREATE FUNCTION ufn_GTFO
(
    @Guid as uniqueidentifier
)
RETURNS VARCHAR(100)
AS
BEGIN
    -- Declare the return variable here
    DECLARE @Result as VARCHAR(100)

    -- Add the T-SQL statements to compute the return value here
    SELECT @Result = 'This is a test'

    -- Return the result of the function
    RETURN @Result
END
GO

И следующая таблица:

CREATE TABLE [dbo].[Test](
    [PKey] [int] IDENTITY(1,1) NOT NULL,
    [WFT] [uniqueidentifier] NULL,
 CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED 
(
    [PKey] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

Скалярная функция ufn_GTFO обычно компонуется, так что следующий C #:

static void ConcreteTest()
{
    DataClasses1DataContext db = new DataClasses1DataContext();
    var q = from t in db.Tests
            select new { t.PKey, GTFO = db.ufn_GTFO(t.WFT) };

    var p = q.ToArray();
}

Переводится на следующий SQL:

SELECT [t0].[PKey], [dbo].[ufn_GTFO]([t0].[WFT]) AS [GTFO] FROM [dbo].[Test] AS [t0]

Однако, если я использую интерфейс refactor -> extract в DataContext и использую его экземпляр:

static void InterfaceTest()
{
    IDataClasses1DataContext db = new DataClasses1DataContext();
    var q = from t in db.Tests
            select new { t.PKey, GTFO = db.ufn_GTFO(t.WFT) };

    var p = q.ToArray();
}

Я получаю следующий SQL, и вызовы ufn_GTFO происходят один раз для каждой записи, так как .ToArray () перечисляет результаты.

SELECT [t0].[PKey], [t0].[WFT] AS [guid]
FROM [dbo].[Test] AS [t0]

Итак, мой вопрос: почему это происходит и что я могу сделать, чтобы предотвратить это, все еще используя интерфейс?

Обновление 1: Я сравнил IL, сгенерированный для конкретного метода, с методом интерфейса, и они отличаются только ссылкой на интерфейс и класс отображения, сгенерированный компилятором, который, кажется, не иметь какое-либо отношение к результату.

1 Ответ

1 голос
/ 17 января 2012

linq to sql в значительной степени опирается на атрибуты для сопоставления членов класса (datacontext) с членами базы данных. Ваши интерфейсы, вероятно, не имеют атрибута FunctionAttribute над методом ufn_GRFO. без этого атрибута связь между миром C # и функцией SQL разрывается; тем не мение. ваш интерфейс также не имеет атрибута DatabaseAttribute, поскольку этот атрибут действителен только для классов, но не для интерфейсов. без этого атрибута вы разорвали связь между C # и всей базой данных. по умолчанию Linq использует AttributeMappingSource для сопоставления элементов типа в DataContext. Смысл в том, что интерфейс является рассматриваемым типом, и этот тип разорвал ссылку на эту базу данных, поскольку вы не можете применить к ней атрибут базы данных, ваш источник отображения по умолчанию не будет сопоставлять функцию ufn_GRFO с функцией базы данных, скорее, linq будет рассматривать его как функцию .NET для вызова с данными из поля WFT.

Я подозреваю, что способ обойти эту проблему - предоставить ваш datacontext с пользовательской реализацией MappingSource, которая игнорирует DatabaseAttribute и рассматривает только атрибуты свойств.

http://msdn.microsoft.com/en-us/library/system.data.linq.mapping.functionattribute.aspx

http://msdn.microsoft.com/en-us/library/system.data.linq.mapping.databaseattribute.aspx

http://msdn.microsoft.com/en-us/library/system.data.linq.mapping.attributemappingsource.aspx

http://msdn.microsoft.com/en-us/library/system.data.linq.mapping.mappingsource.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...