Я ищу способ переопределить метод/процесс SaveChanges в EF. Нам нужно каким-то образом захватить SQL, предотвратить выполнение обычного обновления/удаления/вставки и использовать этот сгенерированный SQL для выполнения нашей пользовательской процедуры.Переопределение EntityFramework SaveChanges - захватить SQL и вызвать пользовательский процесс
- Позвонить
SaveChanges()
как обычно. Пусть EF генерирует SQL. - Получить SQL
- Предотвратить, что SQL от выполняется нормальный путь
- вызов пользовательских хранимых процедур (принимает дополнительные Params и т.д.)
- Притворитесь, как мы выполнили
SaveChanges
(или просто возвращает 0)
Единственная реальная проблема, которую я вижу, - это захват SQL изнутри метода SaveChanges
. Что мы будем делать что-то вроде этого, в идеале ...
- Get поставщика/подключение/и т.д.
- перехватчиков событий установки для обработки этого
- сотворили, не код изменения/переопределение и т.д.
Мы используем MVC4 & EF5 в отношении базы данных аббревиатуры 3 буквы. Дело здесь в том, чтобы избежать ручного кодирования SQL в каждом действии обновления и полагаться на EF, чтобы генерировать все, что для нас. Поскольку процедура берет прямой SQL
Да, это нехороший способ сделать это (единственная процедура), но у нас нет выбора в этом вопросе. Никак нет. Если мы не сможем это сделать, нам нужно будет написать пользовательский sql. Возможно, есть еще один способ, которым мы можем обеспечить это, где мы проходим контекст и сами выполняем эту работу? Тогда мы можем просто проверять, что «SaveChanges()» никогда не называют: D
Решение
Я использовал EFTracingProvider
в качестве отправной точки для создания моего собственного поставщика, который делает это (и некоторые другие вещи). Вы также можете сделать это с помощью только EFTracingProvider, разместив все в своем классе Entities и обрабатывая события. Вы не увидите свой измененный SQL, так как это событие будет срабатывать после него, поэтому вам нужно будет сделать свой собственный журнал. Это было раздели до лучшей подгонки на сайте :)
public class MyEntities : MyBaseEntities
{
public MyEntities(): this(connectionString: "name=MyBaseEntities") {}
public MyEntities(string connectionString)
: base(MakeConnection(connectionString, "EFTracingProvider")) {}
/// <summary>
/// Insert the wrapped connection by calling the base toolkit.
private static EntityConnection MakeConnection(string connectionString, params string[] providers)
{
var conn = EntityConnectionWrapperUtils.CreateEntityConnectionWithWrappers(
connectionString,
providers
);
//get the tracing connection, so that we can attach event handlers
var us = conn.UnwrapConnection<EFTracingConnection>();
if (us != null)
{
us.CommandExecuting += BeforeExecute;
}
return conn;
}
private static void BeforeExecute(object sender, CommandExecutionEventArgs e)
{
// If an Create/Update/Delete action then we need to wrap it in our custom proc
if (IsCudAction(e.CommandTree))
{
var text = cmd.Parameters.Cast<DbParameter>().Aggregate(
cmd.CommandText,
(current, p) => current.Replace(p.ParameterName, SafeSql.Prepare(p.Value)));
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "[dbo].[ExecuteForMe]";
cmd.Parameters.Clear();
cmd.Parameters.AddRange(new[]
{
new SqlParameter("commandText", text),
new SqlParameter("extraInfo", "logging context")
});
}
}
public static bool IsCudAction(DbCommandTree commandTree)
{
if (commandTree is DbUpdateCommandTree) return true;
if (commandTree is DbDeleteCommandTree) return true;
if (commandTree is DbInsertCommandTree) return true;
if (commandTree is DbQueryCommandTree) return false;
if (commandTree is DbFunctionCommandTree) return false;
throw new InvalidOperationException("Unknown type of CommandTree: " + commandTree.GetType().Name);
}
}
Знаете ли вы, что вы можете [сопоставлять красные действия с хранимыми процедурами] (http://weblogs.asp.net/zeeshanhirani/archive/2010/10/14/inserting-updating-and-deleting-entity -Использование сохраненного-procedures.aspx)? Вы можете использовать их для вызова своего центрального sproc. –
@GertArnold Это похоже на то, что стоит опубликовать в качестве ответа. Я бы '+ 1', так или иначе ... –
Я слышал об этом (не использовал его.) Стандарт (и это большой и немного интересный корпус) заключается в использовании этой ОДНОЙ хранимой процедуры, все их многочисленные базы данных. Нам даже не разрешают писать процедуры (и я бы не хотел писать 3 procs для ~ 70 таблиц, а затем вручную их сопоставлять, а также поддерживать их). Теперь, если EF может генерировать те! Вы должны добавить его в качестве ответа, даже если он может оказаться неприменимым для меня (корпоративные ограничения). –