Asp.NetでAdoをキャッシュする.Net Entity
4747 ワード
しばらくの間Ado.Net Entity Frameworkの使用は、その便利さを感じながらも、いくつかの悩みを受けています.その最大の悩みは、AEFの設計理念に由来し、Web開発や同時アクセスの要求に完全に合致しないシステムである.
最も明らかな点はキャッシュに現れます.キャッシュを使用することは、システムデータのインタラクション性能を向上させる最も簡便で有効な方法であるが、Adoをキャッシュしたい場合は.Net Entityは、思ったほど簡単ではありません.例えば、
そう書いたらおめでとうございます.別のコンテキスト環境で修正しようとすると、キャッシュが禁止されていることに気づきます.「1つのエンティティオブジェクトを複数のIEntityChangeTrackerインスタンスで参照することはできません」というメッセージが表示されます.
しかし、元のIEntityChangeTrackerはどこへ行ったのでしょうか.キャッシュを埋め込むときのObjectContextの参照を保持しない限り、削除されることは明らかです.最初は、この問題に対して、新しいEntityで更新し、キャッシュ対応項目を置き換えました.これは、異なるタイプのエンティティクラスの作成が異なるため、多くの煩わしいコードをもたらします.ビジネスロジックがやや複雑な場合は、データベースを更新してキャッシュ同期を更新するプロセスがさらに困難になります.また、変更回数が増えるにつれて、メモリには未解放のObjectContextオブジェクトが大量にあふれています.
AEFでは、エンティティにはステータスがありますが、独自のステータスを管理することはできません.オブジェクトコンテキストに依存して、ステータスマネージャがエンティティのステータスを監視する必要があります.これはNHibernateなどのORMの枠組みとは大きく異なり、国内外のフォーラムで多くの苦情を呼んでいる.AEFチームのこのような設計には彼らの考えがあるかもしれないが、少なくともWeb開発では、確かに不便を招いた.
そこで私は、その面倒なIEntityChangeTrackerインスタンスリファレンスをきれいに除去する方法を考え始めました.反射する方法があります.これはやむを得ない方法です.エンティティがキャッシュに追加される前にDetachを追加するより良い解決策があります.ここでAEF APIのデザインの非人間化を改めて批判せざるを得ないのは、ObjectContextのAttachメソッドがなぜタイプを直接判断してエンティティを追加することができず、エンティティセット名を指定する必要があるのか、本当に理解できないと思います.
キャッシュの期限切れの更新方法を最初に変更します.
次に、独自のObjectContextを作成し、自動的に生成されたエンティティコンテキストクラスを継承します.
これにより、Add/ATtachやDeleteを直接安心して行うことができます.AttachメソッドにはIEntityWithKeyパラメータが必要であり,DeleteObjectとAddObjectのパラメータタイプはobjectであり,これもAEF自身の混乱であるはずである.ここでは、dbなどの各エンティティセットを上書きすることもできない.Products.AddObjectという方法ですが、At Least,it works,and looks nice.アプリケーション開発プログラマーとして、これで十分です.
自分のプログラムを済ませてAEF 5.0の到来を待つ.もしかすると、NHibernateなどのサードパーティのフレームワークも試してみるべきかもしれませんが、AEFには少し畏敬しています.
最も明らかな点はキャッシュに現れます.キャッシュを使用することは、システムデータのインタラクション性能を向上させる最も簡便で有効な方法であるが、Adoをキャッシュしたい場合は.Net Entityは、思ったほど簡単ではありません.例えば、
var db = new DBEntities();
HttpContext.Current.Cache["product"] = db.Products.ToList();
そう書いたらおめでとうございます.別のコンテキスト環境で修正しようとすると、キャッシュが禁止されていることに気づきます.「1つのエンティティオブジェクトを複数のIEntityChangeTrackerインスタンスで参照することはできません」というメッセージが表示されます.
var db = new DBEntites();
var product = = (Cache["product"] as List<Product>).Single(p=>p.PId==id);
db.Attach(product); //
しかし、元のIEntityChangeTrackerはどこへ行ったのでしょうか.キャッシュを埋め込むときのObjectContextの参照を保持しない限り、削除されることは明らかです.最初は、この問題に対して、新しいEntityで更新し、キャッシュ対応項目を置き換えました.これは、異なるタイプのエンティティクラスの作成が異なるため、多くの煩わしいコードをもたらします.ビジネスロジックがやや複雑な場合は、データベースを更新してキャッシュ同期を更新するプロセスがさらに困難になります.また、変更回数が増えるにつれて、メモリには未解放のObjectContextオブジェクトが大量にあふれています.
AEFでは、エンティティにはステータスがありますが、独自のステータスを管理することはできません.オブジェクトコンテキストに依存して、ステータスマネージャがエンティティのステータスを監視する必要があります.これはNHibernateなどのORMの枠組みとは大きく異なり、国内外のフォーラムで多くの苦情を呼んでいる.AEFチームのこのような設計には彼らの考えがあるかもしれないが、少なくともWeb開発では、確かに不便を招いた.
そこで私は、その面倒なIEntityChangeTrackerインスタンスリファレンスをきれいに除去する方法を考え始めました.反射する方法があります.これはやむを得ない方法です.エンティティがキャッシュに追加される前にDetachを追加するより良い解決策があります.ここでAEF APIのデザインの非人間化を改めて批判せざるを得ないのは、ObjectContextのAttachメソッドがなぜタイプを直接判断してエンティティを追加することができず、エンティティセット名を指定する必要があるのか、本当に理解できないと思います.
キャッシュの期限切れの更新方法を最初に変更します.
var db = new DBEntities();
var products = db.Products.ToList();
foreach(var p in products) db.Detach(p);
HttpContext.Current.Cache["product"] = products;
次に、独自のObjectContextを作成し、自動的に生成されたエンティティコンテキストクラスを継承します.
public class CustomDBEntites : DBEntities
{
List<object> AttachedEntities = new List<object>();
static List<Type> CachedTypes; //
static Dictionary<Type, string> EntitySets; //
static CustomDBEntites ()
{
CachedTypes = new List<Type> { typeof(Section) };
EntitySets = new Dictionary<Type, string>();
EntitySets.Add(typeof(Product), "Products");
//.... ....
}
/// <summary>
/// SaveOptions , 。
/// </summary>
/// <param name="options"> System.Data.Objects.SaveOptions 。</param>
public override int SaveChanges(System.Data.Objects.SaveOptions options)
{
try
{
return base.SaveChanges(options);
}
finally
{
foreach (var item in AttachedEntities) this.Detach(item);
}
}
/// <summary>
///
/// </summary>
/// <param name="entity"> </param>
public void Attach(IEntityWithKey entity, EntityState state)
{
var type = entity.GetType();
var cached = CachedTypes.Contains(type);
this.AttachTo(EntitySets[type], entity);
this.ObjectStateManager.ChangeObjectState(entity, state);
// ( )
if (cached && state != EntityState.Deleted) this.AttachedEntities.Add(entity);
}
/// <summary>
/// , 。
/// </summary>
/// <param name="entity"> </param>
public new void Attach(IEntityWithKey entity)
{
Attach(entity, EntityState.Unchanged);
}
/// <summary>
/// , 。
/// </summary>
/// <param name="entity"> </param>
public void AddObject(object entity)
{
Attach(entity as IEntityWithKey, EntityState.Added);
}
/// <summary>
/// , 。
/// </summary>
/// <param name="entity"> </param>
public new void DeleteObject(object entity)
{
Attach(entity as IEntityWithKey, EntityState.Deleted);
}
}
これにより、Add/ATtachやDeleteを直接安心して行うことができます.AttachメソッドにはIEntityWithKeyパラメータが必要であり,DeleteObjectとAddObjectのパラメータタイプはobjectであり,これもAEF自身の混乱であるはずである.ここでは、dbなどの各エンティティセットを上書きすることもできない.Products.AddObjectという方法ですが、At Least,it works,and looks nice.アプリケーション開発プログラマーとして、これで十分です.
自分のプログラムを済ませてAEF 5.0の到来を待つ.もしかすると、NHibernateなどのサードパーティのフレームワークも試してみるべきかもしれませんが、AEFには少し畏敬しています.