从概念上讲,我想映射这样的集合:
HasMany(x => x.Children).Where("some_column_name='foo'");
HasMany() 的默认模式要求我提供一个 KeyColumn,它应该存在于子表中,并且其值应该是父表的标识符值。但是,我不想那样做。我想为连接到这个子表关系提供唯一且完整的sql子句。
可以吗?
我尝试完全从映射中删除 KeyColumn。但是,nHibernate 默认情况下会在生成的 sql 中添加一些内容——它似乎是父类的某种标识符占位符。例如,如果此关系的父类称为“Parent”,则 nH 会生成如下 SQL
从孩子中选择....child0_where([我的自定义where子句,耶])和child0_.Parent_id=?
我希望它停止向此连接添加任何附加子句,并仅使用映射的 .Where() 方法提供的自定义 where 子句。
我不知道确切的情况,所以可能有一个更简单的解决方案,但这应该可行。
使用的课程
class Parent : Entity
{
public virtual IList<Child> Children { get; protected set; } = new List<Child>();
}
class Child : Entity
{
public virtual string ChildType { get; set; }
}
映射
class ParentMap : ClassMap<Parent>
{
public ParentMap()
{
Id(x => x.Id);
HasMany(x => x.Children)
.PropertyRef(nameof(ChildType))
.KeyColumn("ChildType")
.Cascade.All();
Map(x => ChildType).Access.Using<ChildTypeGetter>();
}
public string ChildType { get; set; }
}
class ChildTypeGetter : IPropertyAccessor, IGetter, ISetter
{
public IGetter GetGetter(Type theClass, string propertyName) => this;
public ISetter GetSetter(Type theClass, string propertyName) => this;
public bool CanAccessThroughReflectionOptimizer => false;
public string PropertyName => nameof(ParentMap.ChildType);
public Type ReturnType => typeof(string);
public MethodInfo Method => throw new NotImplementedException();
public object Get(object target) => "foo";
public object GetForInsert(object owner, IDictionary mergeMap, ISessionImplementor session) => Get(owner);
public void Set(object target, object value) { }
}
class ChildMap : ClassMap<Child>
{
public ChildMap()
{
Id(x => x.Id);
Map(x => x.ChildType);
}
}
测试代码
session.Save(new Child { ChildType = "foo" });
session.Save(new Child { ChildType = "foo" });
session.Save(new Child { ChildType = "bar" });
var parentId = session.Save(new Parent());
session.Flush();
session.Clear();
var parent = session.Get<Parent>(parentId);
Assert.Equal(2, parent.Children.Count);