【问题标题】:IDbConnection in instance field and using clause实例字段中的 IDbConnection 和 using 子句
【发布时间】:2015-03-27 08:23:22
【问题描述】:

我正在编写一个与底层数据库进行交互的服务类。我在类构造函数中将连接作为参数传递。

public class MyDbService : IDbService
{
    private readonly IDbConnection _connection;

    public MyDbService(IDbConnection connection)
    {
        _connection = connection;
    }

    public void DoStuff()
    {
        // Sql-Server implementation
        var conn = _connection as SqlConnection;
        if(conn != null)
        {
            using(conn)
            {
                conn.Open();
                // Do stuff
            }
        }

        // Implementation for other providers
        ...
    }
}

DoStuff() 在第一次被调用时工作,但由于using() 子句,conn 对象被释放,当再次调用conn.Open() 时我得到一个InvalidOperationException

我可以通过删除using 并添加conn.Close() 来解决这个问题,但这对我来说似乎是一个“丑陋”的选择?

所以,我有两个问题,第一个是 oop 的基础:

  1. 为什么在我使用using(conn) 时会释放_connection 对象?
  2. 在构造函数中传递连接对象时,什么是“最佳实践”?

编辑:

该类是 WPF 应用程序的一部分。

由于问题似乎与 DI 有关,我已经概述了背后的类。我明白了,我需要传入连接对象的一个​​新实例,因为它在服务中第一次使用后被处理 - 我只是看不到如何(至少在没有将 Unity 容器携带到视图模型和手动解决)。当然,一个非常简单的解决方案是将连接字符串和提供程序传递给服务构造函数,但我想让这种方法以某种方式工作。任何提示都非常感谢:)

App.xaml.cs:

public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            var connString = System.Configuration.ConfigurationManager.ConnectionStrings["LocalTest"].ConnectionString;
            var providerName = System.Configuration.ConfigurationManager.ConnectionStrings["LocalTest"].ProviderName;

            var connection = DbProviderFactories.GetFactory(providerName).CreateConnection();

            if (connection != null)
            {
                connection.ConnectionString = connString;
                var myService= new MyDbService(connection);

                // Register dependency injection
                var container = new UnityContainer();
                container.RegisterInstance<IDbConnection>(connection);
                container.RegisterInstance<IDbService>(myService);


                var mainWindow = container.Resolve<MainWindow>();
                mainWindow.Show();
            }
            else
            {
                // Handle null connection
            }
        }
    }

MainWindow.xaml.cs:

public partial class MainWindow: Window
{
    private MyViewModel _vm;

    public MainWindow()
    {
        InitializeComponent();
    }

    [Dependency]
    public MyViewModel ViewModel
    {
        set
        {
            _vm = value;
            DataContext = _vm;
        }
    }
}

MyViewModel.cs:

public class MyViewModel: INotifyPropertyChanged
{
    private readonly IDbService _dbService;

    public MyViewModel(IDbService dbService)
    {
        _dbService = dbService;
    }

    public void DoStuff()
    {
        _dbService.DoStuff();
    }

    ...

    // Other viewmodel stuff

}

【问题讨论】:

  • 您是否使用Singleton() 生命周期创建连接?
  • 我像这样创建连接:var connection = DbProviderFactories.GetFactory(providerName).CreateConnection() 并通过 Unity DI 传递它
  • 你确定,每次你通过 IDbConnection- 都是新的连接吗?当你第二次调用DoStuff() 时,看起来你从第一次传递到这里的 IDbConnection 已经被处理了。

标签: c# wpf oop


【解决方案1】:

_connection 正在被释放,因为您将它包装在 using 语句中,并且您可能每次都传递相同的实例,因为看起来您创建了一个连接 var connection = ...,然后分别传递相同的变量时间通过 DI。然后在DoStuff 方法中,它被释放,但相同的释放实例被传递到下一个MyDbService

当您设置 DI 而不是返回单个变量(即 connection)时,请尝试返回 DbProviderFactories.GetFactory(providerName).CreateConnection()。这样,每次从 DI 容器请求新的 IDbConnection 时,您总是会得到一个新的数据库实例。

我之前没有使用过 Unity,但您应该将 container.RegisterInstance&lt;IDbConnection&gt;(connection); 更改为使用接受 lambda 表达式的 Register 方法的一个版本,例如:

container.Register&lt;IDbConnection&gt;(c =&gt; DbProviderFactories.GetFactory(providerName).CreateConnection);

以下帖子使用InjectionFactory,并可能提供有关如何执行此操作的有用示例:Registering types with lambda expression

更新 #1:作为旁注,我不会处理连接是 DoStuff。而是实现IDisposable 并在其中处理_connection。然后,这允许您在类的其他方法中重用连接。

更新#2:我也会在您的构造函数中执行您的_connection as SqlConnection,然后将引用存储在_connection 中。如果强制转换失败,则抛出异常。这可确保您在调用者继续使用类的方法/属性之前拥有有效的连接类型。然后,您可以从 DoStuff 方法中删除演员表。

【讨论】:

  • 谢谢你们俩。根据您的 cmets,我意识到我可能在正确注入连接时遇到问题。我会努力解决这个问题并更新帖子。
猜你喜欢
  • 1970-01-01
  • 2012-05-13
  • 2014-01-14
  • 1970-01-01
  • 1970-01-01
  • 2014-10-27
  • 2014-11-09
  • 1970-01-01
  • 2012-01-19
相关资源
最近更新 更多