我们的Asp.net Web应用程序正在使用LINQ-to-SQL(存储过程被拖放到dbml文件上以创建类)和 3层架构类似于下面的架构。我刚刚创建了粗略的方法来给读者提供正确的想法 他能回答得很好。请为我提供更长的代码
namespace MyDataLayer
{
public class MyDataAccess
{
// global instance of datacontext
MyDataModelDataContext myDB = new MyDataModelDataContext(); (#1)
public void GetUserIDByUsername(string sUserName, ref int iUserID)
{
int? iUserIDout = 0;
// this will make call to SP in SQL DB
myDB.USP_RP_GETUSERIDBYUSERNAME(sUserName, "", ref iUserIDout);
iUserID = (int)iUserIDout;
}
public List<USP_APP_USERDETAILSResult> GetUserDetails(string sUserIDs)
{
// this will make call to SP in SQL DB
return myDB.USP_APP_USERDETAILS(sUserIDs).ToList();
}
...
... // several CRUD methods
}
}
namespace MyBusinessLayer
{
public class SiteUser
{
// global DataAccess instance
MyDataLayer.MyDataAccess myDA = new MyDataAccess(); (#2)
public void GetUserIDByUsername(string sUserName, ref int iUserID)
{
myDA.GetUserIDByUsername(sUserName, ref iUserID);
}
public List<USP_APP_USERDETAILSResult> GetUserDetails(string sUserIDs)
{
// this will make call to SP in SQL DB
return myDA.GetUserDetails(sUserIDs);
}
...
... // several CRUD methods
}
}
namespace MyWebApplication
{
public class BaseWebPage : System.Web.UI.Page
{
// static business layer instance
public static MyBusinessLayer.SiteUser UserBLInstance = new SiteUser(); (#3)
...
}
}
// Index.aspx.cs code fragment
namespace MyWebApplication
{
public class Index : BaseWebPage
{
public void PopulateUserDropDown()
{
// using static business layer instance declared in BaseWebPage
List<USP_APP_USERDETAILSResult> listUsers = UserBLInstance.GetUserDetails("1,2,3");
// do databinding and so on ...
}
...
}
}
问题
我们在生产服务器上面临定期的InvalidCastException,这是一个非常简单的方法,如果我从IIS重启我的应用程序,它可以正常工作。当出现此问题时,我们可以从SQL Management Studio访问同一个数据库,并可以执行相同的SP
我们对此问题的主要怀疑是DataContext管理不佳,我在网上阅读了很多关于管理DataContext生命周期的文章,但我现在对各种方法感到困惑。 这就是为什么我已经详细阐述了我的问题,以便许多同样的情况可以清楚地了解问题/答案。
非常感谢
答案 0 :(得分:1)
(参考文献#1)在DataAccess中使用全局datacontext是一种好方法吗?是/否为什么?
是。
但是,在dataaccess类中手动创建它意味着您无法控制datacontext的生存期。而是将其设置为构造函数参数,以便将其注入数据访问
(参考文献#2)在BusinessLayer中使用全局DataAccess实例是一种好方法吗?是/否为什么?
是。但请参阅1. - 通过构造函数使其可注入。
(参考文献#3)在BaseWebPage中声明的静态业务层实例是一种好方法吗?是/否为什么?
没有。避免复杂对象的静态,因为这些对象通常具有非平凡的状态。如果你在并发环境中共享这些对象,就会发生很多令人讨厌的问题。
总结一下。
public class DataAccess {
public DataAccess( DataContext context ) { ... }
}
public class BusinessLayer {
public BusinessLayer( DataAccess access ) { ... }
}
public class MyPage : Page {
...
var ctx = TheDataContext.Current;
var bl = new BusinessLayer( new DataAccess( ctx ) );
}
在请求范围内共享数据上下文:
public partial class TheDataContext {
// Allow the datacontext to be shared in a request-scope
public static TheDataContext Current {
get {
if ( HttpContext.Current.Items["context"] == null )
HttpContext.Current.Items.Add( "context", new TheDataContext() );
return (TheDataContext)HttpContext.Current.Items["context"];
}
}
}
答案 1 :(得分:0)
在您的示例中 - 您的MyDataLayer通常具有名称存储库。当然,在存储库中使用DataContext实例并且不要尝试在外部使用它们。因此,只有在存储库中,您才会依赖Linq-To-Sql,这意味着您可以为这些存储库创建Stub对象,并且非常容易测试应用程序的其他部分。
当然你应该处理你的数据上下文实例,DataContext包含太多的对象来让它们保持活动状态并让GC杀死它们。正如您所看到的,当您使用DataContextes时,您不会创建任何事务对象,因此我认为LinqToSql基于您应该拥有每个事务的所有内容的想法(当然您也可以尝试手动处理事务,但是您真的想要这样做?)。在Repository方法中处理datacontextes是一种很好的方法,因为这不允许您使用所有ORM框架的很酷的功能:Lazy Load。如果您将尝试使用延迟加载 - 您会喜欢它,但通常它只是可能的性能降级原因之一。
肯定你应该使用DataContextes更短或同时使用Request,不要尝试使用LongSession(当你试图为多个Http请求保留DataContext时,它只是痛苦的屁股,没有别的,如果你想阅读这篇文章,试着阅读关于Hibernate中长跑会话的几篇文章,我试过用nHibernate - 不要在家里做这个;))。