NHibernate 3.1 ignoring computed column formula
I have a class with two computed columns. The formulas are select statements that grab counts from other tables, like so:
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.Upd开发者_C百科ate();
});
This was all working fine with Fluent NHibernate 1.1 (using NHibernate 2.1), but I just upgraded to 1.2 (using NH 3.1) and it appears that Fluent NHibernate is ignoring the formulas. I'm getting an "invalid column name" exception for the two fields HasTakenSurvey and Votes because its' trying to query the columns directly rather than executing the formulas as directed. An example query:
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
Did the implementation change? What am I doing wrong?
As noted in the comments ConventionBuilder.Property.Always(x => x.Column(x.Property.Name)) was adding the column to all properties (and overriding the formula).
Adding .Columns.Clear() to the mapping should remove the column, so:
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();
});
Columns.Clear() solution provided by @david duffet also didn't work for me. The getter of Formula is private and so you can't filter on the Formula property (you get method-group cannot be converted to value or something like that). NH3.3, FNH 1.3.
My solution - create a custom Attribute in my Model project - IsNHibernateFormulaPropertyAttribute, apply it to my formula properties, and then check for that attribute in my naming convention logic using reflection:
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));
}
}
精彩评论