同步DataContext,解决linq to sql更新数据的问题
ling to sql更新实体非常费劲! 
一般网上的例子中都是这样的。
但是,貌似在分层系统中,数据库操作会写到数据访问层,定义实体,抽象出接口。
实体类
数据访问接口
但是我在更新的时候出现了问题。
网上也有解决方案,就是加IsVersion字段,感觉怪怪的。所以我认命了,MS让我怎么办我就怎么办,我让一个Request共用一个DataContext实例。
ASP.NET MVC + EntLib4 + LinQ 整合
第一步,把EntLib的Unity作为ASP.NET MVC Controller管理容器。
创建自定义的Controller工厂,通过Unity实力话Controller。
在Global.asax.cs加上初始化UnityContaner的代码。
web.config配置
以上就是整合Unity的代码,EntLib的详细不配置就不贴了。
下面,扩展Unity,Unity的生命周期管理只有,transient,external,singleton,我要增加一个request的,一个request请求一个实例,然后在request介绍的时候,回收资源。
首先,定义自己的DataContext
第二,增加一个Resquest级别的LifetimeManager,HttpContext.Items中数据是Request期间共享数据用的,所以HttpContext.Items中放一个字典,用类型为key,类型的实例为value。如果当前Context.Items中有类型的实例,就直接返回实例。
写一个HttpMoudle,在Request结束的时候回收资源。
最后,把他们变成Unity的扩展。
在webconfig的配置文件中增加
那么在数据访问对象实现就可以这样写
在Controller中也可以直接注入
DataContext本身是有缓存的,整个Request内都是一个DataContext,DataContext一级缓存能力进一步利用,当然,二级缓存才是王道。
一般网上的例子中都是这样的。
Customer cust = db.Customers.First(c => c.CustomerID == "ALFKI"); cust.ContactTitle = "Vice President"; db.SubmitChanges();
但是,貌似在分层系统中,数据库操作会写到数据访问层,定义实体,抽象出接口。
实体类
- /// <summary>
- /// 计划任务
- /// </summary>
- [Table(Name = "EDM_TaskPlan")]
- public class TaskPlan
- {
- /// <summary>
- /// 计划编码
- /// </summary>
- [Column(IsDbGenerated=true,IsPrimaryKey=true,Name="PlanID")]
- public int PlanID { get; set; }
- /// <summary>
- /// 任务名称
- /// </summary>
- [Column(Name="PlanName")]
- public string Name { get; set; }
- /// <summary>
- /// 任务描述
- /// </summary>
- [Column]
- public string Description { get; set; }
- /// <summary>
- /// 星期一定义
- /// </summary>
- [Column]
- public string MondayDef { get; set; }
- /// <summary>
- /// 星期二定义
- /// </summary>
- [Column]
- public string TuesdayDef { get; set; }
- /// <summary>
- /// 星期三定义
- /// </summary>
- [Column]
- public string WednesdayDef { get; set; }
- /// <summary>
- /// 星期四定义
- /// </summary>
- [Column]
- public string ThursdayDef { get; set; }
- /// <summary>
- /// 星期五定义
- /// </summary>
- [Column]
- public string FridayDef { get; set; }
- /// <summary>
- /// 星期六定义
- /// </summary>
- [Column]
- public string SaturdayDef { get; set; }
- /// <summary>
- /// 星期日定义
- /// </summary>
- [Column]
- public string SundayDef { get; set; }
- }
数据访问接口
- /// <summary>
- /// 任务计划数据访问接口
- /// </summary>
- public interface ITaskPlanDao
- {
- /// <summary>
- /// 查找全部
- /// </summary>
- /// <returns></returns>
- TaskPlan[] FindAll();
- /// <summary>
- /// 根据编码查找
- /// </summary>
- /// <param name="id">计划任务编码</param>
- /// <returns></returns>
- TaskPlan FindByID(int id);
- /// <summary>
- /// 保存或更新
- /// </summary>
- /// <param name="taskPlan">任务计划对象</param>
- /// <returns></returns>
- int SaveOrUpdate(TaskPlan taskPlan);
- /// <summary>
- /// 根据编码删除
- /// </summary>
- /// <param name="id">任务计划编码</param>
- /// <returns></returns>
- void DeleteByID(int id);
- }
但是我在更新的时候出现了问题。
- dbContext.Attach(taskPlan);
- //根本不会更新
- dbContext.Attach(taskPlan,true);
- //An entity can only be attached as modified without original state if it //declares a version member or does not have an update check policy
- dbContext.Attach(taskPlan,this.FindByID(taskPlan.PlanID));
- //Cannot add an entity with a key that is already in use.
网上也有解决方案,就是加IsVersion字段,感觉怪怪的。所以我认命了,MS让我怎么办我就怎么办,我让一个Request共用一个DataContext实例。
ASP.NET MVC + EntLib4 + LinQ 整合
第一步,把EntLib的Unity作为ASP.NET MVC Controller管理容器。
创建自定义的Controller工厂,通过Unity实力话Controller。
- /// <summary>
- /// EntLib IoC容器和ASP.NET MVC Controller集成工厂。
- /// </summary>
- public class UnityControllerFactory : DefaultControllerFactory
- {
- private IUnityContainer unityContaier;
- /// <summary>
- ///
- /// </summary>
- /// <param name="unityContaier">EntLib IOC容器</param>
- public UnityControllerFactory(IUnityContainer unityContaier)
- {
- this.unityContaier = unityContaier;
- }
- #region IControllerFactory Members
- protected override IController CreateController(RequestContext context, string controllerName)
- {
- Type type = base.GetControllerType(controllerName);
- return unityContaier.Resolve(type) as IController;
- }
- #endregion
- }
在Global.asax.cs加上初始化UnityContaner的代码。
- protected void Application_Start()
- {
- RegisterRoutes(RouteTable.Routes);
- this.InitializeContainer();
- }
- protected virtual void InitializeContainer()
- {
- IUnityContainer container = new UnityContainer();
- UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
- section.Containers["dataContainer"].Configure(container);
- Type controllerType = typeof(IController);
- foreach (Type type in Assembly.GetExecutingAssembly().GetTypes())
- {
- if (controllerType.IsAssignableFrom(type))
- {
- container.RegisterType(type, type);
- }
- }
- UnityControllerFactory factory = new UnityControllerFactory(container);
- ControllerBuilder.Current.SetControllerFactory(factory);
- }
web.config配置
- <unity>
- <typeAliases>
- <typeAlias alias="transient"
- type="Microsoft.Practices.Unity.TransientLifetimeManager,
- Microsoft.Practices.Unity" />
- </typeAliases>
- <containers>
- <container name="dataContainer">
- <types>
- <type type="Shengjing360.EDM.Task.Daos.ITaskPlanDao,Shengjing360.EDM.Task" mapTo="Shengjing360.EDM.Task.DaoImpl.TaskPlanDaoImpl,Shengjing360.EDM.Task.DaoImpl">
- <lifetime type="transient" />
- </type>
- </types>
- <extensions>
- <add type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.Unity.EnterpriseLibraryCoreExtension, Microsoft.Practices.EnterpriseLibrary.Common" />
- <add type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.Unity.DataAccessBlockExtension, Microsoft.Practices.EnterpriseLibrary.Data" />
- </extensions>
- </container>
- </containers>
- </unity>
以上就是整合Unity的代码,EntLib的详细不配置就不贴了。
下面,扩展Unity,Unity的生命周期管理只有,transient,external,singleton,我要增加一个request的,一个request请求一个实例,然后在request介绍的时候,回收资源。
首先,定义自己的DataContext
- public class ShengjingDataContext : DataContext
- {
- /// <summary>
- ///
- /// </summary>
- /// <param name="db"></param>
- [InjectionConstructor]
- public ShengjingDataContext([Dependency]Database db ) : base(db.CreateConnection())
- {
- this.Database = db;
- this.Log = Console.Out;
- }
- /// <summary>
- /// 数据库
- /// </summary>
- public Database Database { get; private set; }
- }
第二,增加一个Resquest级别的LifetimeManager,HttpContext.Items中数据是Request期间共享数据用的,所以HttpContext.Items中放一个字典,用类型为key,类型的实例为value。如果当前Context.Items中有类型的实例,就直接返回实例。
- public class RequestScopeLifetimeManager : LifetimeManager
- {
- private Type objectType;
- /// <summary>
- ///
- /// </summary>
- /// <param name="t"></param>
- public RequestScopeLifetimeManager(Type t)
- {
- this.objectType = t;
- }
- private IDictionary<Type,object> GetObjectTable()
- {
- IDictionary<Type, object> objects = HttpContext.Current.Items[UnityHttpMoudle.UNITY_OBJECTS]
- as IDictionary<Type, object>;
- if (objects == null)
- {
- lock (this)
- {
- if (HttpContext.Current.Items[UnityHttpMoudle.UNITY_OBJECTS] == null)
- {
- objects = new Dictionary<Type, object>();
- HttpContext.Current.Items[UnityHttpMoudle.UNITY_OBJECTS] = objects;
- }
- else
- {
- return HttpContext.Current.Items[UnityHttpMoudle.UNITY_OBJECTS]
- as IDictionary<Type, object>;
- }
- }
- }
- return objects;
- }
- public override object GetValue()
- {
- IDictionary<Type, object> objects = this.GetObjectTable();
- object obj = null;
- if (objects.TryGetValue(this.objectType,out obj))
- {
- return obj;
- }
- return null;
- }
- public override void RemoveValue()
- {
- IDictionary<Type, object> objects = this.GetObjectTable();
- object obj = null;
- if (objects.TryGetValue(this.objectType, out obj))
- {
- ((IDisposable)obj).Dispose();
- objects.Remove(this.objectType);
- }
- }
- public override void SetValue(object newValue)
- {
- IDictionary<Type, object> objects = this.GetObjectTable();
- objects.Add(this.objectType, newValue);
- }
- }
写一个HttpMoudle,在Request结束的时候回收资源。
- public class UnityHttpMoudle : IHttpModule
- {
- internal const string UNITY_OBJECTS = "UNITY_OBJECTS";
- #region IHttpModule Members
- public void Dispose()
- {
- }
- public void Init(HttpApplication context)
- {
- context.EndRequest += new EventHandler(context_EndRequest);
- }
- private void context_EndRequest(object sender, EventArgs e)
- {
- IDictionary<Type, object> objects = HttpContext.Current.Items[UNITY_OBJECTS]
- as IDictionary<Type, object>;
- if (objects != null)
- {
- foreach (Type key in objects.Keys)
- {
- if (objects[key] is IDisposable)
- {
- ((IDisposable)objects[key]).Dispose();
- }
- }
- HttpContext.Current.Items.Remove(UNITY_OBJECTS);
- }
- }
- #endregion
- }
最后,把他们变成Unity的扩展。
- public class ShengjingExtension : UnityContainerExtension
- {
- protected override void Initialize()
- {
- this.Container.RegisterType<RequestScopeLifetimeManager, RequestScopeLifetimeManager>();
- this.Container.RegisterType<ShengjingDataContext, ShengjingDataContext>(new RequestScopeLifetimeManager(typeof(ShengjingDataContext)));
- }
- }
在webconfig的配置文件中增加
- <unity>
- ……
- <extensions>
- ……
- <add type="Shengjing360.Utility.ShengjingExtension,Shengjing360.Utility" />
- </extensions>
- <unity>
- ……
- <httpModules>
- ……
- <add name="UnityModule" type="Shengjing360.Utility.UnityHttpMoudle,Shengjing360.Utility"/>
- </httpModules>
那么在数据访问对象实现就可以这样写
- public class TaskPlanDaoImpl : ITaskPlanDao
- {
- private ShengjingDataContext dbContext;
- /// <summary>
- ///
- /// </summary>
- /// <param name="dbContext"></param>
- [InjectionConstructor]
- public TaskPlanDaoImpl([Dependency]ShengjingDataContext dbContext)
- {
- this.dbContext = dbContext;
- }
- #region ITaskPlanDao Members
- /// <summary>
- ///
- /// </summary>
- /// <returns></returns>
- public TaskPlan[] FindAll()
- {
- var taskPlans = from taskPlan in dbContext.GetTable<TaskPlan>()
- orderby taskPlan.PlanID descending
- select taskPlan;
- return taskPlans.ToArray<TaskPlan>();
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="id"></param>
- /// <returns></returns>
- public TaskPlan FindByID(int id)
- {
- var taskPlans = from taskPlan in dbContext.GetTable<TaskPlan>()
- where taskPlan.PlanID == id
- select taskPlan;
- if (taskPlans.Count() > 0)
- {
- return taskPlans.First<TaskPlan>();
- }
- return null;
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="taskPlan"></param>
- /// <returns></returns>
- public int SaveOrUpdate(TaskPlan taskPlan)
- {
- Table<TaskPlan> table = this.dbContext.GetTable<TaskPlan>();
- if (taskPlan.PlanID == 0)
- {
- table.InsertOnSubmit(taskPlan);
- }
- this.dbContext.SubmitChanges();
- return taskPlan.PlanID;
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="id"></param>
- public void DeleteByID(int id)
- {
- Table<TaskPlan> table = this.dbContext.GetTable<TaskPlan>();
- table.DeleteOnSubmit(table.First<TaskPlan>(p => p.PlanID == id));
- this.dbContext.SubmitChanges();
- }
- #endregion
- }
在Controller中也可以直接注入
- [Dependency]
- public ITaskPlanDao taskPlanDao { get; set; }
- ……
- /// <summary>
- ///
- /// </summary>
- /// <returns></returns>
- public ActionResult SaveOrUpdate()
- {
- int planID = String.IsNullOrEmpty(this.Request.Form["PlanID"]) ?
- 0 :
- Int32.Parse(this.Request.Form["PlanID"]);
- TaskPlan taskPlan = planID == 0 ?
- new TaskPlan() { PlanID = planID } :
- this.taskPlanDao.FindByID(planID);
- taskPlan.Name = this.Request.Form["Name"].Trim();
- taskPlan.Description = this.Request.Form["Description"].Trim();
- taskPlan.MondayDef = this.Request.Form["MondayDef"].Trim();
- taskPlan.SaturdayDef = this.Request.Form["SaturdayDef"].Trim();
- taskPlan.SundayDef = this.Request.Form["SundayDef"].Trim();
- taskPlan.ThursdayDef = this.Request.Form["ThursdayDef"].Trim();
- taskPlan.TuesdayDef = this.Request.Form["TuesdayDef"].Trim();
- taskPlan.WednesdayDef = this.Request.Form["WednesdayDef"].Trim();
- taskPlan.FridayDef = this.Request.Form["FridayDef"].Trim();
- this.taskPlanDao.SaveOrUpdate(taskPlan);
- return this.RedirectToAction("Browse");
- }
DataContext本身是有缓存的,整个Request内都是一个DataContext,DataContext一级缓存能力进一步利用,当然,二级缓存才是王道。
 
                    
                     
                    
                 
                    
                
 
                
            
         
 
         浙公网安备 33010602011771号
浙公网安备 33010602011771号