NHibernate 3.1忽略计算列公式

4

我有一个类,其中包含两个计算列。公式是选择语句,从其他表中获取计数,如下所示:

private const string VOTES_FORMULA = "(select count(v.id) from Votes v where v.BusinessID = Id)";
private const string SURVEY_FORMULA = "(select cast((case when exists (select * from surveys s where s.businessid = Id) then 1 else 0 end) as bit))";

// in my bootstrap code...
mappings.Override<Business>(map =>
{
    map.IgnoreProperty(x => x.IsNewRecord);
    map.IgnoreProperty(x => x.IdString);
    map.Map(x => x.UserPassword).CustomType<EncryptedStringType>();
    map.Map(x => x.HasTakenSurvey).Formula(SURVEY_FORMULA).Not.Insert().Not.Update();
    map.Map(x => x.Votes).Formula(VOTES_FORMULA).Not.Insert().Not.Update();
});

这在使用Fluent NHibernate 1.1(使用NHibernate 2.1)时都能正常工作,但是我刚刚升级到了1.2(使用NH 3.1),似乎Fluent NHibernate忽略了公式。因为它尝试直接查询列而不执行指定的公式,所以对于HasTakenSurvey和Votes这两个字段,我会得到一个“无效的列名”异常。以下是一个示例查询:

exec sp_executesql N'select TOP (@p0) business0_.Id as Id0_, business0_.UserPassword as UserPass2_0_, business0_.HasTakenSurvey as HasTaken3_0_, business0_.Votes as Votes0_, business0_.Origin as Origin0_, business0_.SecurityToken as Security6_0_, business0_.BusinessName as Business7_0_, business0_.BusinessType as Business8_0_, business0_.BusinessImageUrl as Business9_0_, business0_.BusinessDescription as Busines10_0_, business0_.EmployeeCount as Employe11_0_, business0_.OwnerFirstName as OwnerFi12_0_, business0_.OwnerLastName as OwnerLa13_0_, business0_.UserPosition as UserPos14_0_, business0_.BusinessAddress1 as Busines15_0_, business0_.BusinessAddress2 as Busines16_0_, business0_.BusinessCity as Busines17_0_, business0_.BusinessState as Busines18_0_, business0_.BusinessPostal as Busines19_0_, business0_.BusinessCountry as Busines20_0_, business0_.UserBusinessPhone as UserBus21_0_, business0_.UserMobilePhone as UserMob22_0_, business0_.UserEmailAddress as UserEma23_0_, business0_.UserIpAddress as UserIpA24_0_, business0_.OptInReminders as OptInRe25_0_, business0_.OptInOffers as OptInOf26_0_, business0_.OptInSms as OptInSms0_, business0_.Created as Created0_, business0_.Modified as Modified0_ from dbo.Businesses business0_ order by business0_.BusinessName asc',N'@p0 int',@p0=25

实现是否改变了?我做错了什么?

1
你是否设置了一个FluentNHibernate属性约定,可以为每个属性添加一个列?我以前就被这个问题困扰过,不得不为具有公式的属性添加排除项。 - David Duffett
1
是的,我有ConventionBuilder.Property.Always(x => x.Column(x.Property.Name))。如何从此约定中排除公式列? - Chris
2
你尝试在每个属性的映射覆盖上添加.Columns.Clear()了吗?但是如果所提到的属性约定在映射覆盖之后执行,则可能会出现问题。我在实现IPropertyConvention和IPropertyConventionAcceptance的单独类中设置映射覆盖,并在Accept()方法中排除Formula属性不为null的情况。由于应用约定的顺序不能保证,因此我需要将其与映射中的.Columns.Clear()结合起来。 - David Duffett
Columns.Clear()解决了问题。请发布为答案,以便我可以接受。 :P - Chris
2个回答

2

如评论中所述,ConventionBuilder.Property.Always(x => x.Column(x.Property.Name))会将列添加到所有属性中(并覆盖公式)。

在映射中添加.Columns.Clear()应该可以删除该列,因此:

mappings.Override<Business>(map =>
{
    map.IgnoreProperty(x => x.IsNewRecord);
    map.IgnoreProperty(x => x.IdString);
    map.Map(x => x.UserPassword).CustomType<EncryptedStringType>();
    map.Map(x => x.HasTakenSurvey).Formula(SURVEY_FORMULA).Not.Insert().Not.Update().Columns.Clear();
    map.Map(x => x.Votes).Formula(VOTES_FORMULA).Not.Insert().Not.Update().Columns.Clear();
});

1
Columns.Clear() 对我没有起作用。我不得不实现 IPropertyConvention 接口并过滤公式属性。 - MadRabbit
1
@MadRabbit 你是怎么做到的?能否多说一些? - Bilal Fazlani

0

由@david duffet提供的Columns.Clear()解决方案对我也没有用。Formula的getter是私有的,因此您无法在Formula属性上进行过滤(您会得到方法组无法转换为值或类似的内容)。NH3.3,FNH 1.3。

我的解决方案-在我的Model项目中创建一个自定义属性-IsNHibernateFormulaPropertyAttribute,将其应用于我的公式属性,然后使用反射在我的命名约定逻辑中检查该属性:

private bool IsFormula(IPropertyInstance instance)
{
    var propInfo = instance.Property.DeclaringType.GetProperty(instance.Property.Name);
    if (propInfo != null)
    {
        return Attribute.IsDefined(propInfo, typeof(IsNHibernateFormulaPropertyAttribute));
    }

    return false;
}
public void Apply(IPropertyInstance instance)
    {
        if (!IsFormula(instance))
        {
            instance.Column(Convert(instance.Property.Name));
        }
    }


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接