lilikang

 

同步DataContext,解决linq to sql更新数据的问题

ling to sql更新实体非常费劲!
一般网上的例子中都是这样的。
Customer cust = db.Customers.First(c => c.CustomerID == "ALFKI");
cust.ContactTitle = "Vice President";
db.SubmitChanges();

但是,貌似在分层系统中,数据库操作会写到数据访问层,定义实体,抽象出接口。

实体类
C#代码 复制代码
  1. /// <summary>   
  2. /// 计划任务   
  3. /// </summary>   
  4. [Table(Name = "EDM_TaskPlan")]   
  5. public class TaskPlan   
  6. {   
  7.     /// <summary>   
  8.     /// 计划编码   
  9.     /// </summary>   
  10.     [Column(IsDbGenerated=true,IsPrimaryKey=true,Name="PlanID")]   
  11.     public int PlanID { getset; }   
  12.   
  13.     /// <summary>   
  14.     /// 任务名称   
  15.     /// </summary>   
  16.     [Column(Name="PlanName")]   
  17.     public string Name { getset; }   
  18.   
  19.     /// <summary>   
  20.     /// 任务描述   
  21.     /// </summary>   
  22.     [Column]   
  23.     public string Description { getset; }   
  24.   
  25.     /// <summary>   
  26.     /// 星期一定义   
  27.     /// </summary>   
  28.     [Column]   
  29.     public string MondayDef { getset; }   
  30.   
  31.     /// <summary>   
  32.     /// 星期二定义   
  33.     /// </summary>   
  34.     [Column]   
  35.     public string TuesdayDef { getset; }   
  36.   
  37.     /// <summary>   
  38.     /// 星期三定义   
  39.     /// </summary>   
  40.     [Column]   
  41.     public string WednesdayDef { getset; }   
  42.   
  43.     /// <summary>   
  44.     /// 星期四定义   
  45.     /// </summary>   
  46.     [Column]   
  47.     public string ThursdayDef { getset; }   
  48.   
  49.     /// <summary>   
  50.     /// 星期五定义   
  51.     /// </summary>   
  52.     [Column]   
  53.     public string FridayDef { getset; }   
  54.   
  55.     /// <summary>   
  56.     /// 星期六定义   
  57.     /// </summary>   
  58.     [Column]   
  59.     public string SaturdayDef { getset; }   
  60.   
  61.     /// <summary>   
  62.     /// 星期日定义   
  63.     /// </summary>   
  64.     [Column]   
  65.     public string SundayDef { getset; }   
  66. }  


数据访问接口
C#代码 复制代码
  1. /// <summary>   
  2. /// 任务计划数据访问接口   
  3. /// </summary>   
  4. public interface ITaskPlanDao   
  5. {   
  6.     /// <summary>   
  7.     /// 查找全部   
  8.     /// </summary>   
  9.     /// <returns></returns>   
  10.     TaskPlan[] FindAll();   
  11.   
  12.     /// <summary>   
  13.     /// 根据编码查找   
  14.     /// </summary>   
  15.     /// <param name="id">计划任务编码</param>   
  16.     /// <returns></returns>   
  17.     TaskPlan FindByID(int id);   
  18.   
  19.     /// <summary>   
  20.     /// 保存或更新   
  21.     /// </summary>   
  22.     /// <param name="taskPlan">任务计划对象</param>   
  23.     /// <returns></returns>   
  24.     int SaveOrUpdate(TaskPlan taskPlan);   
  25.   
  26.     /// <summary>   
  27.     /// 根据编码删除   
  28.     /// </summary>   
  29.     /// <param name="id">任务计划编码</param>   
  30.     /// <returns></returns>   
  31.     void DeleteByID(int id);   
  32. }  


但是我在更新的时候出现了问题。
C#代码 复制代码
  1. dbContext.Attach(taskPlan);   
  2. //根本不会更新   
  3. dbContext.Attach(taskPlan,true);   
  4. //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   
  5. dbContext.Attach(taskPlan,this.FindByID(taskPlan.PlanID));   
  6. //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。
C#代码 复制代码
  1. /// <summary>   
  2. /// EntLib IoC容器和ASP.NET MVC Controller集成工厂。   
  3. /// </summary>   
  4. public class UnityControllerFactory : DefaultControllerFactory   
  5. {   
  6.     private IUnityContainer unityContaier;   
  7.   
  8.     /// <summary>   
  9.     ///    
  10.     /// </summary>   
  11.     /// <param name="unityContaier">EntLib IOC容器</param>   
  12.     public UnityControllerFactory(IUnityContainer unityContaier)   
  13.     {   
  14.         this.unityContaier = unityContaier;   
  15.     }  
  16.  
  17.  
  18.     #region IControllerFactory Members   
  19.   
  20.     protected override IController CreateController(RequestContext context, string controllerName)   
  21.     {   
  22.         Type type = base.GetControllerType(controllerName);   
  23.         return unityContaier.Resolve(type) as IController;   
  24.     }  
  25.  
  26.     #endregion   
  27. }  


在Global.asax.cs加上初始化UnityContaner的代码。
C#代码 复制代码
  1. protected void Application_Start()   
  2. {   
  3.     RegisterRoutes(RouteTable.Routes);   
  4.   
  5.     this.InitializeContainer();   
  6. }   
  7.   
  8. protected virtual void InitializeContainer()   
  9. {   
  10.     IUnityContainer container = new UnityContainer();   
  11.   
  12.     UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");   
  13.     section.Containers["dataContainer"].Configure(container);   
  14.   
  15.     Type controllerType = typeof(IController);   
  16.     foreach (Type type in Assembly.GetExecutingAssembly().GetTypes())   
  17.     {   
  18.         if (controllerType.IsAssignableFrom(type))   
  19.         {   
  20.             container.RegisterType(type, type);   
  21.         }   
  22.     }   
  23.   
  24.     UnityControllerFactory factory = new UnityControllerFactory(container);   
  25.     ControllerBuilder.Current.SetControllerFactory(factory);   
  26. }  


web.config配置
Xml代码 复制代码
  1. <unity>  
  2.   <typeAliases>  
  3.     <typeAlias alias="transient"  
  4.          type="Microsoft.Practices.Unity.TransientLifetimeManager,   
  5.            Microsoft.Practices.Unity" />  
  6.   </typeAliases>  
  7.   <containers>  
  8.     <container name="dataContainer">  
  9.       <types>  
  10.         <type type="Shengjing360.EDM.Task.Daos.ITaskPlanDao,Shengjing360.EDM.Task" mapTo="Shengjing360.EDM.Task.DaoImpl.TaskPlanDaoImpl,Shengjing360.EDM.Task.DaoImpl">  
  11.           <lifetime type="transient" />  
  12.         </type>  
  13.       </types>  
  14.       <extensions>  
  15.         <add type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.Unity.EnterpriseLibraryCoreExtension, Microsoft.Practices.EnterpriseLibrary.Common" />  
  16.         <add type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.Unity.DataAccessBlockExtension, Microsoft.Practices.EnterpriseLibrary.Data" />  
  17.       </extensions>  
  18.     </container>  
  19.   </containers>  
  20. </unity>  


以上就是整合Unity的代码,EntLib的详细不配置就不贴了。

下面,扩展Unity,Unity的生命周期管理只有,transient,external,singleton,我要增加一个request的,一个request请求一个实例,然后在request介绍的时候,回收资源。

首先,定义自己的DataContext
C#代码 复制代码
  1. public class ShengjingDataContext : DataContext   
  2. {   
  3.     /// <summary>   
  4.     ///    
  5.     /// </summary>   
  6.     /// <param name="db"></param>   
  7.     [InjectionConstructor]   
  8.     public ShengjingDataContext([Dependency]Database db ) : base(db.CreateConnection())   
  9.     {   
  10.         this.Database = db;   
  11.   
  12.         this.Log = Console.Out;   
  13.     }   
  14.   
  15.     /// <summary>   
  16.     /// 数据库   
  17.     /// </summary>   
  18.     public Database Database { getprivate set; }   
  19. }  

第二,增加一个Resquest级别的LifetimeManager,HttpContext.Items中数据是Request期间共享数据用的,所以HttpContext.Items中放一个字典,用类型为key,类型的实例为value。如果当前Context.Items中有类型的实例,就直接返回实例。
C#代码 复制代码
  1. public class RequestScopeLifetimeManager : LifetimeManager   
  2. {   
  3.     private Type objectType;   
  4.   
  5.     /// <summary>   
  6.     ///    
  7.     /// </summary>   
  8.     /// <param name="t"></param>   
  9.     public RequestScopeLifetimeManager(Type t)    
  10.     {   
  11.         this.objectType = t;   
  12.     }   
  13.   
  14.     private IDictionary<Type,object> GetObjectTable()   
  15.     {   
  16.         IDictionary<Type, object> objects = HttpContext.Current.Items[UnityHttpMoudle.UNITY_OBJECTS]    
  17.             as IDictionary<Type, object>;   
  18.         if (objects == null)   
  19.         {   
  20.             lock (this)   
  21.             {   
  22.                 if (HttpContext.Current.Items[UnityHttpMoudle.UNITY_OBJECTS] == null)   
  23.                 {   
  24.                     objects = new Dictionary<Type, object>();   
  25.                     HttpContext.Current.Items[UnityHttpMoudle.UNITY_OBJECTS] = objects;   
  26.                 }   
  27.                 else  
  28.                 {   
  29.                     return HttpContext.Current.Items[UnityHttpMoudle.UNITY_OBJECTS]   
  30.                         as IDictionary<Type, object>;   
  31.                 }   
  32.             }   
  33.         }   
  34.         return objects;   
  35.     }   
  36.   
  37.     public override object GetValue()   
  38.     {   
  39.         IDictionary<Type, object> objects = this.GetObjectTable();   
  40.         object obj = null;   
  41.         if (objects.TryGetValue(this.objectType,out obj))   
  42.         {   
  43.             return obj;   
  44.         }   
  45.         return null;   
  46.     }   
  47.   
  48.     public override void RemoveValue()   
  49.     {   
  50.         IDictionary<Type, object> objects = this.GetObjectTable();   
  51.         object obj = null;   
  52.         if (objects.TryGetValue(this.objectType, out obj))   
  53.         {   
  54.             ((IDisposable)obj).Dispose();   
  55.             objects.Remove(this.objectType);   
  56.         }   
  57.     }   
  58.   
  59.     public override void SetValue(object newValue)   
  60.     {   
  61.         IDictionary<Type, object> objects = this.GetObjectTable();   
  62.         objects.Add(this.objectType, newValue);   
  63.     }   
  64. }  

写一个HttpMoudle,在Request结束的时候回收资源。
C#代码 复制代码
  1. public class UnityHttpMoudle : IHttpModule   
  2. {   
  3.     internal const string UNITY_OBJECTS = "UNITY_OBJECTS";  
  4.  
  5.     #region IHttpModule Members   
  6.   
  7.     public void Dispose()   
  8.     {   
  9.            
  10.     }   
  11.   
  12.     public void Init(HttpApplication context)   
  13.     {   
  14.         context.EndRequest += new EventHandler(context_EndRequest);   
  15.     }   
  16.   
  17.     private void context_EndRequest(object sender, EventArgs e)   
  18.     {   
  19.         IDictionary<Type, object> objects = HttpContext.Current.Items[UNITY_OBJECTS]    
  20.             as IDictionary<Type, object>;   
  21.         if (objects != null)   
  22.         {   
  23.             foreach (Type key in objects.Keys)   
  24.             {   
  25.                 if (objects[key] is IDisposable)   
  26.                 {   
  27.                     ((IDisposable)objects[key]).Dispose();   
  28.                 }   
  29.             }   
  30.             HttpContext.Current.Items.Remove(UNITY_OBJECTS);   
  31.         }   
  32.     }  
  33.  
  34.     #endregion   
  35. }  

最后,把他们变成Unity的扩展。
C#代码 复制代码
  1. public class ShengjingExtension : UnityContainerExtension   
  2. {   
  3.     protected override void Initialize()   
  4.     {   
  5.         this.Container.RegisterType<RequestScopeLifetimeManager, RequestScopeLifetimeManager>();   
  6.   
  7.         this.Container.RegisterType<ShengjingDataContext, ShengjingDataContext>(new RequestScopeLifetimeManager(typeof(ShengjingDataContext)));   
  8.     }   
  9. }  

在webconfig的配置文件中增加
Xml代码 复制代码
  1. <unity>  
  2. ……   
  3. <extensions>  
  4. ……   
  5. <add type="Shengjing360.Utility.ShengjingExtension,Shengjing360.Utility" />  
  6. </extensions>  
  7. <unity>  
  8. ……   
  9. <httpModules>  
  10. ……   
  11.       <add name="UnityModule" type="Shengjing360.Utility.UnityHttpMoudle,Shengjing360.Utility"/>  
  12.     </httpModules>  


那么在数据访问对象实现就可以这样写
C#代码 复制代码
  1. public class TaskPlanDaoImpl : ITaskPlanDao   
  2. {   
  3.     private ShengjingDataContext dbContext;   
  4.   
  5.     /// <summary>   
  6.     ///    
  7.     /// </summary>   
  8.     /// <param name="dbContext"></param>   
  9.     [InjectionConstructor]   
  10.     public TaskPlanDaoImpl([Dependency]ShengjingDataContext dbContext)   
  11.     {   
  12.         this.dbContext = dbContext;   
  13.     }  
  14.  
  15.     #region ITaskPlanDao Members   
  16.   
  17.     /// <summary>   
  18.     ///    
  19.     /// </summary>   
  20.     /// <returns></returns>   
  21.     public TaskPlan[] FindAll()   
  22.     {   
  23.         var taskPlans = from taskPlan in dbContext.GetTable<TaskPlan>()   
  24.                         orderby taskPlan.PlanID descending   
  25.                         select taskPlan;   
  26.   
  27.         return taskPlans.ToArray<TaskPlan>();   
  28.     }   
  29.   
  30.     /// <summary>   
  31.     ///    
  32.     /// </summary>   
  33.     /// <param name="id"></param>   
  34.     /// <returns></returns>   
  35.     public TaskPlan FindByID(int id)   
  36.     {   
  37.         var taskPlans = from taskPlan in dbContext.GetTable<TaskPlan>()   
  38.                         where taskPlan.PlanID == id   
  39.                         select taskPlan;   
  40.   
  41.         if (taskPlans.Count() > 0)   
  42.         {   
  43.             return taskPlans.First<TaskPlan>();   
  44.         }   
  45.         return null;   
  46.     }   
  47.   
  48.     /// <summary>   
  49.     ///    
  50.     /// </summary>   
  51.     /// <param name="taskPlan"></param>   
  52.     /// <returns></returns>   
  53.     public int SaveOrUpdate(TaskPlan taskPlan)   
  54.     {   
  55.         Table<TaskPlan> table = this.dbContext.GetTable<TaskPlan>();   
  56.         if (taskPlan.PlanID == 0)   
  57.         {   
  58.             table.InsertOnSubmit(taskPlan);   
  59.         }   
  60.   
  61.         this.dbContext.SubmitChanges();   
  62.         return taskPlan.PlanID;   
  63.     }   
  64.   
  65.     /// <summary>   
  66.     ///    
  67.     /// </summary>   
  68.     /// <param name="id"></param>   
  69.     public void DeleteByID(int id)   
  70.     {   
  71.         Table<TaskPlan> table = this.dbContext.GetTable<TaskPlan>();   
  72.         table.DeleteOnSubmit(table.First<TaskPlan>(p => p.PlanID == id));   
  73.         this.dbContext.SubmitChanges();   
  74.     }  
  75.  
  76.     #endregion   
  77. }  


在Controller中也可以直接注入
C#代码 复制代码
  1.         [Dependency]   
  2.         public ITaskPlanDao taskPlanDao { getset; }   
  3.   
  4. ……   
  5.   
  6.         /// <summary>   
  7.         ///    
  8.         /// </summary>   
  9.         /// <returns></returns>   
  10.         public ActionResult SaveOrUpdate()   
  11.         {   
  12.             int planID = String.IsNullOrEmpty(this.Request.Form["PlanID"]) ?   
  13.                 0 :   
  14.                 Int32.Parse(this.Request.Form["PlanID"]);   
  15.   
  16.             TaskPlan taskPlan = planID == 0 ?   
  17.                 new TaskPlan() { PlanID = planID } :   
  18.                 this.taskPlanDao.FindByID(planID);   
  19.   
  20.             taskPlan.Name = this.Request.Form["Name"].Trim();   
  21.             taskPlan.Description = this.Request.Form["Description"].Trim();   
  22.             taskPlan.MondayDef = this.Request.Form["MondayDef"].Trim();   
  23.             taskPlan.SaturdayDef = this.Request.Form["SaturdayDef"].Trim();   
  24.             taskPlan.SundayDef = this.Request.Form["SundayDef"].Trim();   
  25.             taskPlan.ThursdayDef = this.Request.Form["ThursdayDef"].Trim();   
  26.             taskPlan.TuesdayDef = this.Request.Form["TuesdayDef"].Trim();   
  27.             taskPlan.WednesdayDef = this.Request.Form["WednesdayDef"].Trim();   
  28.             taskPlan.FridayDef = this.Request.Form["FridayDef"].Trim();   
  29.   
  30.             this.taskPlanDao.SaveOrUpdate(taskPlan);   
  31.             return this.RedirectToAction("Browse");   
  32.         }  

DataContext本身是有缓存的,整个Request内都是一个DataContext,DataContext一级缓存能力进一步利用,当然,二级缓存才是王道。

posted on 2008-10-21 20:23  KangKang  阅读(1410)  评论(0)    收藏  举报

导航