Table-具有相同 ID 的每个子类对象在缓存中发生冲突
Table-per-subclass objects with same id collide in cache
我需要使用 Fluent NHibernate 映射遗留 table。我无法控制 table 结构。
table 看起来像这样:
TypeId ObjectId Data
10 1 ... //Cat 1
10 2 ... //Cat 2
20 1 ... //Dog 1
30 1 ...
我正在尝试使用 table-per-subclass 结构来映射它,使用 TypeId
的鉴别器值。
public abstract class Animal
{
public virtual int ObjectId { get; set; }
public virtual string Data { get; set; }
}
public class AnimalMap : ClassMap<Animal>
{
public AnimalMap()
{
Table("MyAnimals");
Id(x => x.ObjectId);
Map(x => x.Data);
DiscriminateSubClassesOnColumn("TypeId")
.AlwaysSelectWithValue();
}
}
public class Cat : Animal
{
}
public class CatMap : SubclassMap<Cat>
{
public CatMap()
{
DiscriminatorValue("10");
}
}
public class Dog : Animal
{
}
public class DogMap : SubclassMap<Dog>
{
public DogMap()
{
DiscriminatorValue("20");
}
}
当我尝试在 Dog 1
之后加载 Cat 1
时出现问题,反之亦然。
var a = session.Get<Dog>(1); //Dog1
var b = session.Get<Cat>(1); //null
如果我在抓到第二只动物之前驱逐了第一只动物,它就成功了。
var a = session.Get<Dog>(1); //Dog1
session.Evict(a);
var b = session.Get<Cat>(1); //Cat1
当我将 Dog
和 Cat
映射到我的 AnimalHome
class 时,出现以下异常:
Unable to cast object of type 'MyNamespace.Dog' to type
'MyNamespace.Cat'.
这让我相信缓存不会根据类型区分 Dog
和 Cat
。它只是将其视为 Animal 1
并且 Cat 1
等于 Dog 1
。
我能否以某种方式让缓存考虑实际的子class?
或者,如果使用 table-per-subclass 结构不可能做到这一点,我应该如何映射这个 table?
我通过放弃鉴别器解决了这个问题。
Where
映射更适合我的情况,因为我实际上不需要在我的代码中将 Dog
或 Cat
视为 Animal
。
我仍然通过继承 Animal
相关的映射将代码重复保持在最低限度。
public class AnimalMap<T> : ClassMap<T>
where T : Animal
{
public AnimalMap()
{
Table("MyAnimals");
Id(x => x.ObjectId);
Map(x => x.Data);
}
}
public class CatMap : AnimalMap<Cat>
{
public CatMap()
{
Where("TypeId = 10");
}
}
缓存现在知道 Cat
不是 Dog
。
我需要使用 Fluent NHibernate 映射遗留 table。我无法控制 table 结构。
table 看起来像这样:
TypeId ObjectId Data
10 1 ... //Cat 1
10 2 ... //Cat 2
20 1 ... //Dog 1
30 1 ...
我正在尝试使用 table-per-subclass 结构来映射它,使用 TypeId
的鉴别器值。
public abstract class Animal
{
public virtual int ObjectId { get; set; }
public virtual string Data { get; set; }
}
public class AnimalMap : ClassMap<Animal>
{
public AnimalMap()
{
Table("MyAnimals");
Id(x => x.ObjectId);
Map(x => x.Data);
DiscriminateSubClassesOnColumn("TypeId")
.AlwaysSelectWithValue();
}
}
public class Cat : Animal
{
}
public class CatMap : SubclassMap<Cat>
{
public CatMap()
{
DiscriminatorValue("10");
}
}
public class Dog : Animal
{
}
public class DogMap : SubclassMap<Dog>
{
public DogMap()
{
DiscriminatorValue("20");
}
}
当我尝试在 Dog 1
之后加载 Cat 1
时出现问题,反之亦然。
var a = session.Get<Dog>(1); //Dog1
var b = session.Get<Cat>(1); //null
如果我在抓到第二只动物之前驱逐了第一只动物,它就成功了。
var a = session.Get<Dog>(1); //Dog1
session.Evict(a);
var b = session.Get<Cat>(1); //Cat1
当我将 Dog
和 Cat
映射到我的 AnimalHome
class 时,出现以下异常:
Unable to cast object of type 'MyNamespace.Dog' to type 'MyNamespace.Cat'.
这让我相信缓存不会根据类型区分 Dog
和 Cat
。它只是将其视为 Animal 1
并且 Cat 1
等于 Dog 1
。
我能否以某种方式让缓存考虑实际的子class? 或者,如果使用 table-per-subclass 结构不可能做到这一点,我应该如何映射这个 table?
我通过放弃鉴别器解决了这个问题。
Where
映射更适合我的情况,因为我实际上不需要在我的代码中将 Dog
或 Cat
视为 Animal
。
我仍然通过继承 Animal
相关的映射将代码重复保持在最低限度。
public class AnimalMap<T> : ClassMap<T>
where T : Animal
{
public AnimalMap()
{
Table("MyAnimals");
Id(x => x.ObjectId);
Map(x => x.Data);
}
}
public class CatMap : AnimalMap<Cat>
{
public CatMap()
{
Where("TypeId = 10");
}
}
缓存现在知道 Cat
不是 Dog
。