Как определить модель данных как переменную SQL, а не таблицу или представление в EF Core?C#

Место общения программистов C#
Ответить
Anonymous
 Как определить модель данных как переменную SQL, а не таблицу или представление в EF Core?

Сообщение Anonymous »

Я не могу выяснить, правильно ли я определил модель данных как переменную SQL, а не таблицу или представление, в EF Core, потому что хранящаяся процедура SQL Server и веб -приложение Blazor успешно общаются друг с другом. < /p>

Я использую SQL Server 2017 и .NET 9, здесь My Model:
P> P> P> P> P> P> P> P> P> P> P> P> P> P> P> P> P> P> P> P> P> P> P> P> P> P> P> P> P> Pre Server 2017 и .NET 9, здесь. class = "lang-cs prettyprint-override">

Код: Выделить всё

[Keyless]
public class SqlOutput
{
[Column("SP_OUTPUT")]
public string? SpOutput { get; set; }
}
А вот как я установил модель данных sqloutput в DBContext :

Код: Выделить всё

public DbSet RandText { get; set; } = default!;

public DbSet SqlOutput { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity()
.HasNoKey()
.ToView(null);
}
В моем проекте randtext фактически включен, так как именно здесь размещаются записи таблиц.
Я ожидал, что EF Core рассматривает данную модель данных как ввод переменной из сохраненной процедуры, и не как объект таблицы или представление. />

Код: Выделить всё

CREATE PROCEDURE myStoredProcedure
@id INT,
@random_text VARCHAR(50),
@key VARCHAR(100)
AS
BEGIN
SET NOCOUNT ON;

DECLARE @successful VARCHAR(20) = 'SUCCESSFUL';

IF @key = 'SEE_DET'
BEGIN

SELECT id ,random_text ,dt_stamp
FROM myDB.dbo.myTable
WHERE id = @id AND disable = 0

END

ELSE IF @key = 'ADD_NEW_REC'
BEGIN

BEGIN TRY

INSERT INTO myDB.dbo.myTable (random_text)
VALUES (@random_text)

IF @@ROWCOUNT > 0
BEGIN

SELECT @successful AS SP_OUTPUT

END

END TRY
BEGIN CATCH

SELECT CAST(NULL AS VARCHAR(20)) AS SP_OUTPUT

END CATCH

END

ELSE IF @key = 'MOD_REC'
BEGIN

UPDATE myDB.dbo.myTable
SET random_text = @random_text
WHERE id = @id AND disable = 0

IF @@ROWCOUNT > 0
BEGIN

SELECT @successful AS SP_OUTPUT

END

ELSE
BEGIN

SELECT NULL AS SP_OUTPUT -- I leave it as is to exhibit the original form that's answered and corrected by Charlieface

END

END

ELSE IF @key = 'DEL_UPD'
BEGIN

UPDATE myDB.dbo.myTable
SET disable = 1
WHERE id = @id AND disable = 0

IF @@ROWCOUNT > 0
BEGIN

SELECT @successful AS SP_OUTPUT

END

END

ELSE
BEGIN

SELECT CONCAT('@key parameter value: ', '''', @key, '''', ' cannot be found.') AS SP_OUTPUT -- Here's how I catch an invalid argument of @key parameter

END
END
Вы можете заметить, что я старался не включать условие else в соответствии с else @key = 'del_upd' , чтобы увидеть, как оно ведет себя. Я также рассмотрел Casting null с Varchar (как предложено Charlieface) в рамках Begin Catch ... End Catch , потому что в этом случае я смоделировал таким образом, чтобы нарушить код не null

Код: Выделить всё

SqlOutput? output = await someClass.SomeMethod("myStoredProcedure", id, admin?.RandomText, "MOD_REC");
somemethod определяется как,

Код: Выделить всё

public async Task SomeMethod(string spName, params object?[] parameters) {...}
< /code>
, поскольку я стремлюсь свести к минимуму условно -исходную код, но все же гарантируя, что он может обрабатывать нулевые типы вместе с другими типами данных в объекте  Single < /em> Params? SQLParameter [] 
, чья длина я определена на основе объекта Params? [] длины, а также на основе соответствующей определения хранимой процедуры.

Код: Выделить всё

var paramDefs = new (string Name, SqlDbType Type, int? Size)[]
{
("id", SqlDbType.Int, null),
("random_text", SqlDbType.VarChar, 50),
("key", SqlDbType.VarChar, 100)
};
и я затем передаю параметры методу с помощью типа SQLParameter [] возврата в формат выражения коллекции:

Код: Выделить всё

return [.. paramDefs
.Select((def, i) =>
{
var param = def.Size is null
? new SqlParameter(def.Name, def.Type)
: new SqlParameter(def.Name, def.Type, def.Size.Value);

param.Value = parameters[i] ?? DBNull.Value;
return param;
})];
< /code>
Я инициализировал его таким образом: < /p>
public static SqlParameter[] SomeStaticMethod((string Name, SqlDbType Type, int? Size)[] paramDefs, params object?[] parameters) {...}
, а затем я интерполировал эти свойства из somestaticmethod с $ "exec {spname}" , чтобы получить соответствующий экземпляр formattablestring с помощью Spectame :

pre Class = "lang-csle- Praite-cole-cs.

Код: Выделить всё

public static FormattableString SomeOtherStaticMethod(string spName, SqlParameter[] sqlParameters) {
return sqlParameters.Length switch
{
1 => $"EXEC {spName} {sqlParameters[0]}",
2 => $"EXEC {spName} {sqlParameters[0]}, {sqlParameters[1]}",
3 => $"EXEC {spName} {sqlParameters[0]}, {sqlParameters[1]}, {sqlParameters[2]}",
_ => throw new ArgumentException("Too many parameters provided."),
};
}
Интересно, что приведенный выше код заключается в том, что операторы Switch рефактируются и в формат выражения сбора, поэтому заслужите команду .net для этого :).
Использование какого-то ComeTherStaticMethod returned antemple, я инициализировал его:
Praite-qued-aeprinde-uprinde-uprede-

Код: Выделить всё

FormattableString sqlParam = SomeStaticClass.SomeOtherStaticMethod(spName, sqlParameter);

var result = await _context.SqlOutput
.FromSql(sqlParam)
.ToListAsync();

return result.FirstOrDefault();
В этом отношении сценарий оператора ожидаемого выполняется должным образом, что означает, что он обновляет или не обновляет соответствующие записи, как и ожидалось.

Код: Выделить всё

SqlOutput? output = await someClass.SomeMethod("myStoredProcedure", id, admin?.RandomText, "MOD_REC");
смоделированная версия, чтобы запустить условие else из sp:

Код: Выделить всё

SqlOutput? output = await someClass.SomeMethod("myStoredProcedure", -1, admin?.RandomText, "MOD_REC");
Однако ответ, который должен быть либо успешным , либо null , не то, что я получаю. Вместо этого он дает этот результат из раздела переменных во время отладки с использованием точки останова:


admin.RandomText" class="text-danger" />

Save



}

Back to List

role="alert" aria-live="assertive" aria-atomic="true" data-bs-delay="1000">


Successfully modified!





class="toast align-items-center text-bg-danger border-0 position-fixed bottom-0 end-0 mb-3 me-3" role="alert"
aria-live="assertive" aria-atomic="true" data-bs-delay="1000">


Someting went wrong. Please try again later.






window.showLiveToast = () => {
const toastEl = document.getElementById('liveToast');
if (toastEl) {
const toast = bootstrap.Toast.getOrCreateInstance(toastEl);
toast.show();

toastEl.addEventListener('hidden.bs.toast', () => {
window.location.replace('/sql_server/crud/admin_pages');
});
}
};
window.showLiveToastError = () => {
const toastEl = document.getElementById('liveToastError');
if (toastEl) {
const toast = bootstrap.Toast.getOrCreateInstance(toastEl);
toast.show();
}
};


@code {
private RandText? admin = new();
private SQLServerContext context = default!;

[SupplyParameterFromQuery(Name = "userid")]
private int id { get; set; }
private SqlOutput? output;

protected override async Task OnInitializedAsync()
{
context = DbFactory.CreateDbContext();
var someClass = new SomeClass(context);
admin = await someClass.SomeMethod("myStoredProcedure", id, null,
"SEE_DET");

if (admin is null)
{
NavigationManager.NavigateTo("notfound");
}
}

private async Task UpdateAdmin()
{
context = DbFactory.CreateDbContext();
var someClass = new SomeClass(context);

try
{
output = await someClass.SomeMethod("myStoredProcedure", id, admin?.RandomText,
"MOD_REC");

if (output?.SpOutput is null) // null or other explicit data response from SP is crucial in my use case
{
await JS.InvokeVoidAsync("showLiveToastError");
return;
}
await JS.InvokeVoidAsync("showLiveToast");
}
catch (DbUpdateConcurrencyException) // I'm not sure if this is needed
{
Console.WriteLine("Concurrency issue occurred.");
}
}

private void DisposeToastThenNavigate()
{
NavigationManager.NavigateTo("/navigate_back_to_list", replace: true);
}

public async ValueTask DisposeAsync()
{
await context.DisposeAsync();
}
}
< /code>
SomeClass.cs[/code]:

Код: Выделить всё

using Microsoft.EntityFrameworkCore;
using MyProject.Models.SQLServer;
using MyProject.Data.SQLServer;
using System.Data;
using Microsoft.Data.SqlClient;

class SomeClass(SQLServerContext context)
{
private readonly SQLServerContext _context = context;
public async Task SomeMethod(string spName, params object?[] parameters)
{
var paramDefs = new (string Name, SqlDbType Type, int? Size)[]
{
("id", SqlDbType.Int, null),
("random_text", SqlDbType.VarChar, 50),
("key", SqlDbType.VarChar, 100)
};

SqlParameter[] sqlParameter = SomeStaticClass.SomeStaticMethod(paramDefs, parameters);

if (parameters.Length != sqlParameter.Length)
{
throw new ArgumentException("Parameters count mismatch.");
}

FormattableString sqlParam = SomeStaticClass.SomeOtherStaticMethod(spName, sqlParameter);

var result = await _context.SqlOutput
.FromSql(sqlParam)
.ToListAsync();

return result.FirstOrDefault();
}
}
< /code>
SomeStaticClass.cs
:

Код: Выделить всё

using System.Data;
using Microsoft.Data.SqlClient;

static class SomeStaticClass
{
public static SqlParameter[] SomeStaticMethod((string Name, SqlDbType Type, int? Size)[] paramDefs, params object?[] parameters)
{
return [..  paramDefs
.Select((def, i) =>
{
var param = def.Size is null
? new SqlParameter(def.Name, def.Type)
: new SqlParameter(def.Name, def.Type, def.Size.Value);

param.Value = parameters[i] ?? DBNull.Value;
return param;
})];
}

public static FormattableString SomeOtherStaticMethod(string spName, SqlParameter[] sqlParameters)
{
return sqlParameters.Length switch
{
1 => $"EXEC {spName} {sqlParameters[0]}",
2 => $"EXEC {spName} {sqlParameters[0]}, {sqlParameters[1]}",
3 => $"EXEC {spName} {sqlParameters[0]}, {sqlParameters[1]}, {sqlParameters[2]}",
// ... you can add more here...
_ => throw new ArgumentException("Too many parameters provided."),
};
}
}
< /code>

Вот следующие варианты использования, которые, возможно, ожидают для меня, чтобы преодолеть: < /p>

[*]  Есть  огромная возможность < /em> infice inser и обновление и обновление SQL (например, Tran ... Peran < /p>). /> < /li>
  nullability < /em> аргументов имеет решающее значение для обработки пустых данных. контроль. />   Неправильно ли я определяю модель данных, или я что -то упускаю здесь? эти варианты использования?

  Я ошибаюсь в обеспечении настраиваемости модели данных и структуры алгоритма в веб -приложении Blazor из -за нескольких случаев операторов в огромной коллекции сценариев в SQL Server? Если @function_key = 'add_new_rec' 
блок условия, он показывает, что он обрабатывает оператор соответствующим образом без введения какой -либо неточности (как я его проверял несколько раз). Почему это происходит? Вы можете спросить почему я делаю это; Это просто потому, что я человек, который также несет ответственность за управление этими сценариями SQL в RDBM, хотя существует крутой обходной путь, проходя глубокий поиск и проведенный тщательным анализом. К сожалению, я уже смущался и немного разочарован.>

Подробнее здесь: https://stackoverflow.com/questions/797 ... in-ef-core
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»