EF Core переопределить логику идентификации с использованием InterceptorC#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 EF Core переопределить логику идентификации с использованием Interceptor

Сообщение Anonymous »

Я на ранних стадиях преобразования приложения .NET Framework в .net 8+. Это поэтапный проект, поэтому на данном этапе я пытаюсь перейти от Entity Framework 6 на EF Core 3.1 (последняя версия, которая может нацелиться на .net Standard 2.0). < /P>
Существующее приложение делает некоторые странные вещи с столбцами идентификации. Вместо того, чтобы полагаться на реализацию идентификации идентификации SQL Server, iDbCommandTreeInterceptor и dbcommandInterceptor используется для перехвата оператора вставки и добавления пользовательского SQL для заполнения (и получения генерируемого значения) для любого столбца, который не в порядке, но идентификационный столб. Опция из -за ограничений вне моего контроля. Кроме того, следует отметить, что столбцы в базе данных не настроены в виде столбцов идентификации и не имеют значений по умолчанию. Вот как они настроены на модели EF.public class IdentityTreeInterceptor : IDbCommandTreeInterceptor
{
public void TreeCreated(DbCommandTreeInterceptionContext interceptionContext)
{
if (interceptionContext == null)
{
throw new ArgumentNullException(nameof(interceptionContext));
}

if (interceptionContext.OriginalResult.DataSpace == DataSpace.SSpace)
{
var insertCommand = interceptionContext.Result as DbInsertCommandTree;
if (insertCommand != null)
{
if (!HasPrimaryKeyClause(insertCommand))
{
bool hasChanges = false;
List revisedSetClauses =
new List(insertCommand.SetClauses)
{ CreateSetClauseForIdentityColumn(insertCommand, ref hasChanges) };

if (hasChanges)
{
var command = new DbInsertCommandTree(
insertCommand.MetadataWorkspace,
insertCommand.DataSpace,
insertCommand.Target,
new ReadOnlyCollection(revisedSetClauses),
insertCommand.Returning);

interceptionContext.Result = command;
}
}
}
}
}

private DbModificationClause CreateSetClauseForIdentityColumn(DbInsertCommandTree insertCommand, ref bool hasChanges)
{
EdmProperty keyMember = GetIdentityKey(insertCommand.Target.VariableType.EdmType);
if (keyMember != null && (keyMember.TypeName == "int" || keyMember.TypeName == "smallint"))
{
TypeUsage tableType = insertCommand.Target.VariableType;
string storeTableName = tableType.EdmType.MetadataProperties.GetValue("TableName", true).Value.ToString();
string storePkName = keyMember.Name;

string newIdSql = CreateNewIdStatement(keyMember, storeTableName, storePkName);

hasChanges = true;
return DbExpressionBuilder.SetClause(
DbExpressionBuilder.Property(
DbExpressionBuilder.Variable(tableType, insertCommand.Target.VariableName), keyMember.Name),
DbExpressionBuilder.Invoke(CreateFakeFunction(), DbExpression.FromString(newIdSql)));
}

return null;
}

private string CreateNewIdStatement(EdmProperty keyMember, string storeTableName, string storePrimaryKeyName)
{
if (ShouldUseSmallKey(keyMember.TypeName, storeTableName))
{
return $"DECLARE @newId smallint EXEC @newId = GetNextSmallKey '{storeTableName}', '{storePrimaryKeyName}';";
}

return $"DECLARE @newId int EXEC @newId = GetNextKey '{storeTableName}', '{storePrimaryKeyName}';";
}

private bool ShouldUseSmallKey(string keyType, string storeTableName)
{
return keyType == "smallint";
}

private bool HasPrimaryKeyClause(DbInsertCommandTree insertCommand)
{
string keyName = GetPrimaryKeyColumnName(insertCommand.Target.VariableType.EdmType);
foreach (DbSetClause setClause in insertCommand.SetClauses)
{
if (IsMatchingColumnName(setClause, keyName))
{
return true;
}
}

return false;
}

private string GetPrimaryKeyColumnName(EdmType tableSchema)
{
var keys = (IList)tableSchema.MetadataProperties.GetValue("KeyMembers", true).Value;
return (keys.Count == 1) ? keys[0].Name : null;
}

private bool IsMatchingColumnName(DbSetClause clause, string columnName)
{
if (!(clause.Property is DbPropertyExpression))
{
return false;
}

var expression = clause.Property as DbPropertyExpression;
string clauseColumnName = expression.Property.Name;
return columnName == clauseColumnName;
}

private EdmProperty GetIdentityKey(EdmType tableSchema)
{
var keys = (IList)tableSchema.MetadataProperties.GetValue("KeyMembers", true).Value;
if (keys.Count == 1 && keys[0].IsStoreGeneratedIdentity)
{
return keys[0] as EdmProperty;
}

return null;
}

private EdmFunction CreateFakeFunction()
{
FunctionParameter[] returnParameters = new FunctionParameter[]
{
FunctionParameter.Create("id", EdmType.GetBuiltInType(BuiltInTypeKind.FunctionParameter), ParameterMode.ReturnValue)
};
FunctionParameter[] parameters = new FunctionParameter[]
{
FunctionParameter.Create("fakeParam", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String), ParameterMode.In)
};

var payload = new EdmFunctionPayload()
{
ParameterTypeSemantics = ParameterTypeSemantics.AllowImplicitConversion,
IsComposable = true,
Parameters = parameters,
ReturnParameters = returnParameters
};

return EdmFunction.Create("FakeFunction", "MyAppDb", DataSpace.SSpace, payload, null);
}
}

public class IdentitySqlInterceptor : DbCommandInterceptor
{
public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext interceptionContext)
{
if (command == null)
{
return;
}

int parmIndex = -1;
foreach (DbParameter parm in command.Parameters)
{
parmIndex++;
if (parm.Direction == ParameterDirection.Input && parm.Value.ToString().Contains("DECLARE @newId"))
{
Regex _regex = new Regex("(DECLARE @newId.*;)(.*)");

string newIdCommand = _regex.Match(parm.Value.ToString()).Result("$0");
command.CommandText = $"{newIdCommand} {command.CommandText.Replace($"@{parmIndex}", "@newId")}";
parm.Value = string.Empty;
break;
}
}
}
}
< /code>

Я попытался поиграть с пользовательскими генераторами значений, но они выполняются, когда элемент добавляется в контекст, а не когда фактические операторы вставки выполняются < /p>

Подробнее здесь: https://stackoverflow.com/questions/795 ... nterceptor
Реклама
Ответить Пред. темаСлед. тема

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

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

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

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

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

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