2016-10-28 68 views
3

IDbCommandInterceptor接口没有很好的记录。而我只发现了一些稀缺的教程就可以了:连接IDbInterceptor到EntityFramework DbContext只有一次

等几个问题:


这些都是挂钩我已经找到了建议:

- 静态DbInterception类:

DbInterception.Add(new MyCommandInterceptor()); 

- 做上述建议在DbConfiguration

public class MyDBConfiguration : DbConfiguration { 
    public MyDBConfiguration() { 
     DbInterception.Add(new MyCommandInterceptor()); 
    } 
} 

- 使用配置文件:

<entityFramework> 
    <interceptors> 
    <interceptor type="EFInterceptDemo.MyCommandInterceptor, EFInterceptDemo"/> 
    </interceptors> 
</entityFramework> 

虽然我无法弄清楚如何挂钩DbConfiguration类转换为DbContext,并且既不要在配置方法的type部分放置什么。 Another example I found似乎表明,你写一个记录器的命名空间:

type="System.Data.Entity.Infrastructure.Interception.DatabaseLogger, EntityFramework" 

我注意到,DataBaseLogger实现IDisposableIDbConfigurationInterceptor
IDbInterceptorIDbCommandInterceptor还实现IDbInterceptor,所以我尝试(没有成功),像这样格式化:

type="DataLayer.Logging.MyCommandInterceptor, DataLayer" 

当我直接调用静态DbInterception类,它增加了一个拦截器每次呼叫。所以,我的快速和肮脏的解决办法是使用静态构造函数:

//This partial class is a seperate file from the Entity Framework auto-generated class, 
//to allow dynamic connection strings 
public partial class MyDbContext // : DbContext 
{ 
    public Guid RequestGUID { get; private set; } 

    public MyDbContext(string nameOrConnectionString) : base(nameOrConnectionString) 
    { 
     DbContextListeningInitializer.EnsureListenersAdded(); 

     RequestGUID = Guid.NewGuid(); 
     //Database.Log = m => System.Diagnostics.Debug.Write(m); 
    } 

    private static class DbContextListeningInitializer 
    { 
     static DbContextListeningInitializer() //Threadsafe 
     { 
      DbInterception.Add(new MyCommandInterceptor()); 
     } 
     //When this method is called, the static ctor is called the first time only 
     internal static void EnsureListenersAdded() { } 
    } 
} 

但什么是正确的/打算如何做到这一点?

回答

5

我想通了,我DbContext类只是需要有DbConfigurationType属性,在运行时附加配置:

[DbConfigurationType(typeof(MyDBConfiguration))] 
public partial class MyDbContext // : DbContext 
{ 
    public MyDbContext(string nameOrConnectionString) : base(nameOrConnectionString) 
    { } 
} 

public class MyDBConfiguration : DbConfiguration { 
    public MyDBConfiguration() { 
     this.AddInterceptor(new MyCommandInterceptor()); 
    } 
} 
+0

我不认为这是线程安全的。如果另一个线程有MyDBConfiguration2和一个类似的构造函数体,会发生什么?那么这两个DbContext的都会有MyCommandInterceptor注册两次,对吧? –

+1

在你的'MyDBConfiguration'构造函数中,你不必使用那个静态类,你有'this.AddInterceptor()'方法。 –

+0

@JohnZabroski你的意思是说DbInterception.Add()不是线程安全的? [文档](https://msdn.microsoft.com/en-us/library/system.data.entity.infrastructure.interception.dbinterception.add(v = vs.113).aspx)并不这么说,所以我会认为你是对的。 Jan'splite'K的建议看起来像是合乎逻辑的答案 - 我对它进行了测试以确认它是否有效。相应地更新答案。 –

0

docs表明,你可以把它放在Application_Start

protected void Application_Start() 
{ 
    AreaRegistration.RegisterAllAreas(); 
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 
    RouteConfig.RegisterRoutes(RouteTable.Routes); 
    BundleConfig.RegisterBundles(BundleTable.Bundles); 
    DbInterception.Add(new SchoolInterceptorTransientErrors()); 
    DbInterception.Add(new SchoolInterceptorLogging()); 
} 

重要的是它只被调用一次。