AOP的兩個應用:實體集更新(DateEntityListUpdate)、延遲加載(LazyLoad)(上)
在FaibClass.Data中,有兩個AOP的應用,它們分別是實體集更新(DateEntityListUpdate)、延遲加載 (LazyLoad),目前的DataEntity繼承於ContextBoundObject,剛剛從網上看到ContextBoundObject的損耗非常大,但自己測試了一下,應該說影響不是很大,所以暫時不打算使用靜態注入了。
注,兩個AOP都采用Attribute--Property--Sink的結構,每個類的具體功能請查閱相關的技術資料。
一、實體集更新(DateEntityListUpdate)
在前台設置一個實體的屬性,我們在更新整個實體集到數據庫的時候,並不知道哪些屬性更改過,如果全部更新,將造成不必要的浪費,所以引入了這個概念。如果我們不這樣做,模型類的每個屬性set後將添加一句代碼AddUpdateColumn。
這裡使用了.Net的消息鏈進行處理,因為實體類上還可能使用了其他的AOP。
EntityListUpdatableAttribute類
//*******************************************************************
// 模塊:指示實體對象可被集合更新
// 日期:2009-7-29 1:05
// 作者:Faib
// 版權:Copyright Faib Studio 2009
// 官網:http://www.faib.net.cn
// 郵箱:[email protected]
// 備注:
//*******************************************************************
using System;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Remoting.Activation;
using FaibClass.Data.Aspect;
namespace FaibClass.Data
{
/// <summary>
/// 指示實體的屬性更改後,可以使用Update更新整個實體集,如果不指定此特性,實體的DataState無法置為Modified。
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]
public class EntityListUpdatableAttribute : Attribute, IContextAttribute, IContextProperty
{
internal static string propertyName = "EntityListUpdatable";
/// <summary>
/// 構造屬性。
/// </summary>
public EntityListUpdatableAttribute()
{
}
string IContextProperty.Name
{
get { return propertyName; }
}
void IContextProperty.Freeze(Context newContext)
{
}
bool IContextProperty.IsNewContextOK(Context newCtx)
{
return true;
}
void IContextAttribute.GetPropertiesForNewContext(IConstructionCallMessage ctorMsg)
{
IContextProperty interceptProperty = new EntityListUpdatableProperty();
ctorMsg.ContextProperties.Add(interceptProperty);
}
bool IContextAttribute.IsContextOK(Context ctx, IConstructionCallMessage ctorMsg)
{
if (ctx.GetProperty(propertyName) == null)
{
return false;
}
return true;
}
}
}
EntityListUpdatableProperty類
//*******************************************************************
// 模塊:實體集更新的上下文屬性
// 日期:2009-9-19 14:24:24
// 作者:Faib
// 版權:Copyright Faib Studio 2009
// 官網:http://www.faib.net.cn
// 郵箱:[email protected]
// 備注:
//*******************************************************************
using System;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Contexts;
namespace FaibClass.Data.Aspect
{
/// <summary>
/// 實體集更新的上下文屬性。
/// </summary>
internal class EntityListUpdatableProperty : IContextProperty, IContributeObjectSink
{
void IContextProperty.Freeze(Context newContext)
{
}
string IContextProperty.Name
{
get { return EntityListUpdatableAttribute.propertyName; }
}
bool IContextProperty.IsNewContextOK(Context newCtx)
{
EntityListUpdatableProperty property =
newCtx.GetProperty(EntityListUpdatableAttribute.propertyName) as EntityListUpdatableProperty;
if (property == null)
{
return false;
}
return true;
}
IMessageSink IContributeObjectSink.GetObjectSink(MarshalByRefObject obj, IMessageSink nextSink)
{
IMessageSink sink = new EntityListUpdatableSink(obj, nextSink);
return sink;
}
}
}
EntityListUpdatableSink類
//*******************************************************************
// 模塊:用於處理屬性修改後的消息接收器
// 日期:2009-9-19 14:24:12
// 作者:Faib
// 版權:Copyright Faib Studio 2009
// 官網:http://www.faib.net.cn
// 郵箱:[email protected]
// 備注:
//*******************************************************************
using System;
using System.Reflection;
using System.Runtime.Remoting.Messaging;
namespace FaibClass.Data.Aspect
{
/// <summary>
/// 用於處理屬性修改後的消息接收器。
/// </summary>
internal class EntityListUpdatableSink : IMessageSink
{
private IMessageSink m_nextSink;
private MarshalByRefObject m_target;
private static object syncRoot = new object();
public EntityListUpdatableSink(MarshalByRefObject target, IMessageSink nextSink)
{
lock (syncRoot)
{
m_target = target;
m_nextSink = nextSink;
}
}
public IMessage SyncProcessMessage(IMessage msg)
{
IMethodReturnMessage returnedMessage;
HandleMessage(msg, false, out returnedMessage);
return returnedMessage;
}
public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
{
IMethodReturnMessage returnedMessage;
HandleMessage(msg, true, out returnedMessage);
return m_nextSink.AsyncProcessMessage(msg, replySink);
}
public IMessageSink NextSink
{
get { return m_nextSink; }
}
private void HandleMessage(IMessage msg, bool IsAsync, out IMethodReturnMessage returnedMessage)
{
returnedMessage = null;
if (!IsAsync)
{
if (msg is IMethodCallMessage)
{
IMethodCallMessage mcm = (IMethodCallMessage)msg;
bool isFill = (bool)m_target.GetType().GetProperty("InnerIsFill", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(m_target, null);
bool isProperty = !isFill && ((mcm.MethodName.Length > 4 &&
mcm.MethodName.Substring(0, 4) == "set_" && mcm.MethodName != "set_InnerIsFill" &&
mcm.MethodName != "set_InnerDataState" &&
mcm.MethodName != "set_InnerData") || mcm.MethodName == "FieldSetter");
object oldvalue = null, newvalue = null;
MemberInfo minfo = null;
string propertyName = string.Empty;
//取原來的值
if (isProperty)
{
if (mcm.MethodName == "FieldSetter")
propertyName = mcm.InArgs[1].ToString();
else
propertyName = mcm.MethodName.Replace("set_", "");
minfo = Utility.GetMember(m_target.GetType(), propertyName);
if (minfo == null)
isProperty = false;
else if (minfo.IsDefined(typeof(DataColumnAttribute), true))
oldvalue = Utility.GetMemberValue(m_target, minfo, propertyName);
}
returnedMessage = (IMethodReturnMessage)m_nextSink.SyncProcessMessage(msg);
if (isProperty)
{
//新的值
newvalue = Utility.GetMemberValue(m_target, minfo, propertyName);
if (!newvalue.Equals(oldvalue))
{
//調用內部方法添加修改了的列
m_target.GetType().InvokeMember("AddUpdateColumn", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, m_target, new object[] { mcm.MethodName.Replace("set_", "") });
}
}
}
else
{
returnedMessage = (IMethodReturnMessage)m_nextSink.SyncProcessMessage(msg);
}
}
else
{
returnedMessage = null;
}
}
}
}
二、延遲加載(LazyLoad)
沒有仔細研究過其他框架的延遲加載是怎麼實現的,自己還是基於.Net的消息機制做了這個功能。
LazyLoadableAttribute類
//*******************************************************************
// 模塊:延遲加載的屬性
// 日期:2009-9-19 14:23:22
// 作者:Faib
// 版權:Copyright Faib Studio 2009
// 官網:http://www.faib.net.cn
// 郵箱:[email protected]
// 備注:
//*******************************************************************
using System;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Remoting.Activation;
using FaibClass.Data.Aspect;
namespace FaibClass.Data
{
/// <summary>
/// 指示該實體中的子實體集、引用實體、引用屬性可延遲載入。
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class LazyLoadableAttribute : Attribute, IContextAttribute, IContextProperty
{
internal static string propertyName = "LazyLoadable";
/// <summary>
/// 構造屬性。
/// </summary>
public LazyLoadableAttribute()
{
}
string IContextProperty.Name
{
get { return propertyName; }
}
void IContextProperty.Freeze(Context newContext)
{
}
bool IContextProperty.IsNewContextOK(Context newCtx)
{
return true;
}
void IContextAttribute.GetPropertiesForNewContext(IConstructionCallMessage ctorMsg)
{
IContextProperty interceptProperty = new LazyLoadableProperty();
ctorMsg.ContextProperties.Add(interceptProperty);
}
bool IContextAttribute.IsContextOK(Context ctx, IConstructionCallMessage ctorMsg)
{
if (ctx.GetProperty(propertyName) == null)
{
return false;
}
return true;
}
}
}
LazyLoadableProperty類
//*******************************************************************
// 模塊:延遲加載的上下文屬性
// 日期:2009-9-19 14:09:46
// 作者:Faib
// 版權:Copyright Faib Studio 2009
// 官網:http://www.faib.net.cn
// 郵箱:[email protected]
// 備注:
//*******************************************************************
using System;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Contexts;
namespace FaibClass.Data.Aspect
{
/// <summary>
/// 延遲加載的上下文屬性。
/// </summary>
internal class LazyLoadableProperty : IContextProperty, IContributeObjectSink
{
void IContextProperty.Freeze(Context newContext)
{
}
string IContextProperty.Name
{
get { return LazyLoadableAttribute.propertyName; }
}
bool IContextProperty.IsNewContextOK(Context newCtx)
{
LazyLoadableProperty property =
newCtx.GetProperty(LazyLoadableAttribute.propertyName) as LazyLoadableProperty;
if (property == null)
{
return false;
}
return true;
}
IMessageSink IContributeObjectSink.GetObjectSink(MarshalByRefObject obj, IMessageSink nextSink)
{
IMessageSink sink = new LazyLoadableSink(obj, nextSink);
return sink;
}
}
}