C# 实例字段和using子句中的IDbConnection
我正在编写一个服务类,与底层数据库进行一些交互。我将连接作为类构造函数中的参数传递C# 实例字段和using子句中的IDbConnection,c#,wpf,oop,C#,Wpf,Oop,我正在编写一个服务类,与底层数据库进行一些交互。我将连接作为类构造函数中的参数传递 public class MyDbService : IDbService { private readonly IDbConnection _connection; public MyDbService(IDbConnection connection) { _connection = connection; } public void DoStuff
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
我可以通过移除使用和关闭连接来解决这个问题,但这对我来说似乎是一个丑陋的选择
因此,我有两个问题,第一个是oop的基本问题:
当我使用usingconn时,为什么要处理_连接对象?
在构造函数中传递连接对象的最佳实践是什么?
编辑:
该类是WPF应用程序的一部分
由于问题似乎与DI有关,因此我概述了后面的类。我得到,我需要传入连接对象的一个新实例,因为它在服务中第一次使用后就被释放了-我只是看不出,至少在不将Unity容器带到viewmodel并手动解析的情况下是如何处理的。当然,一个非常简单的解决方案是将连接字符串和提供者传递给服务构造函数,但我希望以某种方式使这种方法起作用。如有任何提示,我们将不胜感激:
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
}
}
}
MyViewModel.cs:
public class MyViewModel: INotifyPropertyChanged
{
private readonly IDbService _dbService;
public MyViewModel(IDbService dbService)
{
_dbService = dbService;
}
public void DoStuff()
{
_dbService.DoStuff();
}
...
// Other viewmodel stuff
}
正在释放_连接,因为您正在将其包装在using语句中,并且每次都可能传递相同的实例,因为它看起来像是您创建了一个连接var connection=。。。然后每次通过DI传递相同的变量。然后在DoStuff方法中,它被释放,但是同一个被释放的实例被传递到下一个MyDbService中
当您设置DI而不是返回单个变量(即连接)时,请尝试返回dbProviderFactorys.GetFactoryproviderName.CreateConnection。这样,每次从DI容器请求新的IDbConnection时,您都会得到一个新的数据库实例
我以前没有使用Unity,但您应该更改container.RegisterInstanceconnection;要使用接受lambda表达式的Register方法版本,例如:
container.Registerc=>dbProviderFactorys.GetFactoryproviderName.CreateConnection
以下帖子使用InjectionFactory,并可能提供一个关于如何执行此操作的有用示例:
更新1:作为旁注,我不会处理DoStuff连接。而是实现IDisposable并在其中处理_连接。这样,您就可以在类的其他方法中重用连接
更新2:我还将在构造函数中以SqlConnection的形式进行_连接,然后在_连接中存储引用。如果强制转换失败,则抛出异常。这确保在调用方继续使用类的方法/属性之前,您拥有有效的连接类型。然后可以从DoStuff方法中删除强制转换。是否使用Singleton lifecycle创建连接?我创建的连接如下:var connection=dbProviderFactorys.GetFactoryproviderName.CreateConnection,并通过Unity Dia将其传入。您确定每次传递IDbConnection时都是新连接吗?当你们第二次打电话给DoStuff时,看起来你们从第一次打过来的IDB连接已经处理好了。谢谢你们两位。根据您的评论,我意识到正确注入连接可能会有问题。我会努力工作并更新帖子。
public class MyViewModel: INotifyPropertyChanged
{
private readonly IDbService _dbService;
public MyViewModel(IDbService dbService)
{
_dbService = dbService;
}
public void DoStuff()
{
_dbService.DoStuff();
}
...
// Other viewmodel stuff
}