[英]Initializing constructor from stored cache in C#
我不確定確切如何描述這個問題,但是這里有。 我有一個映射到SQLite數據庫中的對象的類層次結構。 我已經編寫了在.NET對象和數據庫之間進行通信的所有重要代碼。
我有一個基本界面,如下所示:
public interface IBackendObject
{
void Read(int id);
void Refresh();
void Save();
void Delete();
}
這是對任何對象的基本CRUD操作。 然后,我實現了一個封裝了許多功能的基類。
public abstract class ABackendObject : IBackendObject
{
protected ABackendObject() { } // constructor used to instantiate new objects
protected ABackendObject(int id) { Read(id); } // constructor used to load object
public void Read(int id) { ... } // implemented here is the DB code
}
現在,最后,我有了具體的子對象,每個子對象在數據庫中都有自己的表:
public class ChildObject : ABackendObject
{
public ChildObject() : base() { }
public ChildObject(int id) : base(id) { }
}
到目前為止,這對於我的所有目的都可以正常工作。 該子級有幾種回調方法,基類使用這些方法正確地實例化數據。
我現在想使它稍微有效。 例如,在以下代碼中:
public void SomeFunction1()
{
ChildObject obj = new ChildObject(1);
obj.Property1 = "blah!";
obj.Save();
}
public void SomeFunction2()
{
ChildObject obj = new ChildObject(1);
obj.Property2 = "blah!";
obj.Save();
}
在這種情況下,我將構造兩個全新的內存實例,並且根據SomeFunction1和SomeFunction2調用的順序,可能不會保存Property1或Property2。 我想要實現的是使這兩個實例都以某種方式指向相同的內存位置的方法-如果使用“ new”關鍵字,我認為這是不可能的,因此我一直在尋找有關如何進行。
理想情況下,我想將所有已加載對象的緩存存儲在ABackendObject
類中,並在請求時返回對已加載對象的內存引用,或者如果該對象尚不存在,則從內存中加載該對象並將其添加到緩存中。 我已經有很多代碼已經在使用這個框架,所以我當然必須更改很多東西才能使它正常工作,但是我只想一些有關如何進行的技巧。
謝謝!
如果要存儲已加載對象的“緩存”,則可以輕松地讓每種類型維護一個Dictionary<int, IBackendObject>
來保存已加載對象, Dictionary<int, IBackendObject>
其ID鍵。
而不是使用構造函數,而是建立一個檢查緩存的工廠方法:
public abstract class ABackendObject<T> where T : class
{
public T LoadFromDB(int id) {
T obj = this.CheckCache(id);
if (obj == null)
{
obj = this.Read(id); // Load the object
this.SaveToCache(id, obj);
}
return obj;
}
}
如果您將基類設為泛型且將Read虛擬化,則應該能夠提供大多數此功能,而無需過多的代碼重復。
您想要的是一個對象工廠。 將ChildObject
構造函數設為私有,然后編寫一個靜態方法ChildObject.Create(int index)
,該方法返回ChildObject
,但在內部確保具有相同索引的不同調用返回相同的對象。 對於簡單的情況,索引=>對象的簡單靜態哈希就足夠了。
如果使用的是.NET Framework 4,則可能需要查看System.Runtime.Caching
命名空間,該命名空間為您提供了非常強大的緩存體系結構。
http://msdn.microsoft.com/zh-CN/library/system.runtime.caching.aspx
聽起來非常適合像這樣的參考人數...
#region Begin/End Update
int refcount = 0;
ChildObject record;
protected ChildObject ActiveRecord
{
get
{
return record;
}
set
{
record = value;
}
}
public void BeginUpdate()
{
if (count == 0)
{
ActiveRecord = new ChildObject(1);
}
Interlocked.Increment(ref refcount);
}
public void EndUpdate()
{
int count = Interlocked.Decrement(ref refcount);
if (count == 0)
{
ActiveRecord.Save();
}
}
#endregion
#region operations
public void SomeFunction1()
{
BeginUpdate();
try
{
ActiveRecord.Property1 = "blah!";
}
finally
{
EndUpdate();
}
}
public void SomeFunction2()
{
BeginUpdate();
try
{
ActiveRecord.Property2 = "blah!";
}
finally
{
EndUpdate();
}
}
public void SomeFunction2()
{
BeginUpdate();
try
{
SomeFunction1();
SomeFunction2();
}
finally
{
EndUpdate();
}
}
#endregion
我認為您或多或少在正確的軌道上。 您可以創建一個工廠來創建子對象(並可以跟蹤“活動”實例),也可以跟蹤已保存的實例,以便在調用Save方法時可以識別出ChildObject
的第一個實例是與您的ChildObject
的第二個實例相同,並且將數據從第二個實例復制到第一個實例。 從編碼的角度來看,這兩個都是相當重要的,而且都可能涉及在實體上覆蓋相等方法。 我傾向於認為使用第一種方法不太可能導致錯誤。
另一種選擇是使用現有的Obect-Relational映射包(例如NHibernate或Entity Framework)在對象和數據庫之間進行映射。 我知道NHibernate支持Sqlite,根據我的經驗,它往往是對實體結構進行最少更改的對象。 通過這種方法,您將獲得ORM層跟蹤實例的好處(並為您生成SQL),此外,您可能會獲得一些當前數據訪問代碼可能沒有的更高級的功能。 不利之處在於這些框架往往具有與之相關的學習曲線,並且取決於您所使用的框架,這可能會對您的其余代碼產生不小的影響。 因此,值得將收益與學習框架並將代碼轉換為使用API的成本進行權衡。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.