0

У меня есть метод действий контроллера, который возвращает IQueryable< AnswerDTO>, у которого есть поле под названием «Sequence». Я хочу установить это поле после некоторых вычислений. Мой подход:Выполнение некоторых операций внутри оператора Select в LINQ

var answer = from dfi in _db.DiaryFormInstances 
//Some Query with LINQ 
select new AnswerDTO() 
{ 
    Value = dfit.Value, 
    //How to perform this operation? 
    Sequence = Convert.ToInt32(fti.ItemName.Substring(fti.ItemName.LastIndexOf("_")+1)), 
    LastModifiedDate = dfit.LastModifiedDate.Value, 
    LastModifiedByID = dfit.LastModifiedByID.Value 
}; 

Как установить свойство Sequence, подобное этому в выражении select select?

Sequence = Convert.ToInt32(fti.ItemName.Substring(fti.ItemName.LastIndexOf("_")+1)) 

Если я выполняю запрос в своем методе действий, то я могу легко выполнить эту операцию. Но я хочу вернуть IQueryable, и я не хочу выполнять запрос внутри моего метода действий.

Я хочу, чтобы web api выполнил запрос, и после выполнения он правильно установит свойство Sequence.

+0

Я вижу 'dfi' определено в запросе, но не используется в операторе отбора, тогда как' 'dfit' и fti' используются, но не определены – Moho

+0

Emdadul, я добавил еще более надежный ответ что я тестировал в небольшом приложении на своей машине. Я удалил свой предыдущий ответ, поскольку, как оказалось, необходимые функции не были доступны в Linq для Entities. –

ответ

1

После изучения функций, доступных в Linq для лиц, кажется, что извлекая число в том, как вы хотите это не возможно с тем, что встроенный.

Лучше всего, чтобы создать пользовательскую функцию в БД, что вы может позвонить. Для этого необходимо сначала создать следующую функцию в вашей базе данных (вы можете создать его непосредственно с помощью SSMS, например):

CREATE FUNCTION ExtractSequence 
(
    @sequenceString NVARCHAR(50) 
) 
RETURNS INT 
AS 
BEGIN 
    RETURN CAST(RIGHT(@sequenceString, CHARINDEX('_', REVERSE('_' + @sequenceString)) - 1) AS INT) 
END 
GO 

Далее вам нужно будет включить https://codefirstfunctions.codeplex.com/ пакет, это на NuGet, просто искать CodeFirstStoreFunctions.

После того, как вы добавили вышеуказанный пакет, вам нужно добавить modelBuilder.Conventions.Add(new FunctionsConvention("dbo", this.GetType())); в метод OnModelCreating вашего класса контекста, например.

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.Conventions.Add(new FunctionsConvention("dbo", this.GetType())); 
} 

Далее вам необходимо добавить следующие строки в классе контекста, а также:

// First parameter should always be CodeFirstDatabaseSchema, this is just a convention used by the store functions package 
// The second parameter should match the name of the function in the DB. You can call the method something else but I'd keep it the same as the function name too 
[DbFunction("CodeFirstDatabaseSchema", "ExtractSequence")] 
public static int ExtractSequence(string sequenceString) 
{ 
    // No need to provide an implementation as this is like a placeholder for the DB function you created in the DB in the first step 
    throw new NotSupportedException(); 
} 

Наконец, вы можете использовать новую функцию в Linq для выражения сущностей, так что вы хотите изменить ваш выбор искать что-то вроде:

var answer = from dfi in _db.DiaryFormInstances 
select new AnswerDTO() 
{ 
    Value = dfit.Value, 
    Sequence = MyDbContext.ExtractSequence(fti.ItemName), // Change MyDbContext to whatever your context class is 
    LastModifiedDate = dfit.LastModifiedDate.Value, 
    LastModifiedByID = dfit.LastModifiedByID.Value 
}; 
Смежные вопросы