Castle ActiveRecord 3.0 を使用していますが、オブジェクト参照をデータベースから取得するときに問題が発生します。同じ SessionScope 内で複数のエンティティをフェッチすると、関連するエンティティに対して同じオブジェクト参照が取得されます。
しかし、多くの場合、必要なすべてのオブジェクトを取得するために同じセッション スコープを使用することはできません。説明するのはちょっと難しいので、以下に例を示します。
[ActiveRecord(Table = "car")]
public class Car : ActiveRecordLinqBase<Car>
{
[PrimaryKey("id")]
public virtual int Id { get; set; }
[OneToOne(PropertyRef = "Car", Cascade = CascadeEnum.SaveUpdate)]
public virtual Location Location { get; set; }
}
[ActiveRecord("location")]
public class Location : ActiveRecordLinqBase<Location>
{
[PrimaryKey(Column = "id")]
public virtual int Id { get; set; }
[BelongsTo("car_id", NotFoundBehaviour = NotFoundBehaviour.Ignore,
Cascade = CascadeEnum.SaveUpdate)]
public virtual Car Car { get; set; }
}
[ActiveRecord(Table = "move_order")]
public class MoveOrder : ActiveRecordLinqBase<MoveOrder>
{
[PrimaryKey(Column = "id")]
public virtual int Id { get; set; }
[BelongsTo(Column = "car_id")]
public virtual Car Car { get; set; }
[BelongsTo(Column = "destination_id")]
public virtual Location Destination { get; set; }
}
最初にいくつかのオブジェクトを作成しています:
using (new SessionScope())
{
var car = new Car() { };
var initialLocation = new Location() { Car = car };
initialLocation.Save();
var destinationLocation = new Location();
destinationLocation.Save();
}
次に、同じ車/場所に対して 2 つの移動命令を作成すると、問題なく動作します。
MoveOrder moveOrder;
MoveOrder moveOrder2;
using (new SessionScope())
{
moveOrder = new MoveOrder()
{
Destination = Location.Queryable.First(x => x.Car == null),
Car = Car.Queryable.First();
};
moveOrder2 = new MoveOrder()
{
Destination = Location.Queryable.First(x => x.Car == null),
Car = Car.Queryable.First()
};
}
オブジェクト参照は、次のものと同じです。
- moveOrder.Car、moveOrder2.Car
- moveOrder.Location、moveOrder2.Location
しかし、異なるセッション スコープを使用して両方の MoveOrder を取得すると、次のようになります。
using (new SessionScope())
{
moveOrder = new MoveOrder()
{
Destination = Location.Queryable.First(x => x.Car == null),
Car = Car.Queryable.First()
};
}
と
using (new SessionScope())
{
moveOrder2 = new MoveOrder()
{
Destination = Location.Queryable.First(x => x.Car == null),
Car = Car.Queryable.First()
};
}
これらのプロパティはどれも参照が同じではありませんが、論理的には同じエンティティです。また、Nhibernate セッションを取得し、切り離されたすべてのオブジェクトを新しいセッションに関連付けてみました。
using (var sess = GetSession())
{
sess.Lock(moveOrder.Destination, LockMode.Read);
sess.Lock(moveOrder.Car, LockMode.Read);
moveOrder2 = new MoveOrder()
{
Destination = sess.Get<Location>(moveOrder.Destination.Id),
Car = sess.Get<Car>(moveOrder.Car.Id),
};
}
この場合はこれでうまくいきますが、いくつかの問題があります。
- 現在使用しているすべてのデータベースエンティティを新しいセッションに渡す必要があります
- クエリ、session.Get は Id に対して機能しません
主な質問は次のとおりです。
同じエンティティ (同じ ID) をフェッチするたびに、DB から同じオブジェクト参照を取得するにはどうすればよいですか?
Cache = CacheEnum.ReadWrite
また、AR init で構成し、すべての db クラス ActiveRecord 属性に追加することで、Nhibernate の第 2 レベル キャッシュを使用しようとしましたが、結果はありませんでした。
同じセッションを常に開いたままにしないでください。