[b]ling to sql更新实体非常费劲![/b]
一般网上的例子中都是这样的。
但是,貌似在分层系统中,数据库操作会写到数据访问层,定义实体,抽象出接口。
实体类
数据访问接口
但是我在更新的时候出现了问题。
网上也有解决方案,就是加IsVersion字段,感觉怪怪的。所以我认命了,MS让我怎么办我就怎么办,[b]我让一个Request共用一个DataContext实例[/b]。
[b]ASP.NET MVC + EntLib4 + LinQ 整合[/b]
第一步,把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让我怎么办我就怎么办,[b]我让一个Request共用一个DataContext实例[/b]。
[b]ASP.NET MVC + EntLib4 + LinQ 整合[/b]
第一步,把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一级缓存能力进一步利用,当然,二级缓存才是王道。