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

[b]ling to sql更新实体非常费劲![/b]
一般网上的例子中都是这样的。

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一级缓存能力进一步利用,当然,二级缓存才是王道。
阅读更多
文章标签: Linq SQL ASP.net ASP C#
个人分类: .NET
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭