2013-07-10 2 views
1

Linq to SQL усекает десятичный тип, а не округляет его. По-видимому, это expected behavior. Чтобы обойти это, я округляю значение в своем коде C#. Например, скажем, у меня есть следующее:Linq to SQL вызывает хрупкую связь с базой данных

public class Foo 
{ 
    public decimal SomeNumber { get; set; } 
} 

Тип базы данных для SomeNumber десятичный (9,5). Эта точность была бизнес-решением, сделанным заказчиком.

Если SomeNumber является .00079547 в коде, L2S обрезает его до .00079 при отправке запроса на SQL Server. Мне нужно, чтобы число было округлено до 0,00080. Для того, чтобы сделать это, у меня есть этот метод в моем коде:

private static decimal RoundToMatchSqlServerPrecision(decimal numberToRound) 
{ 
    const int roundingPlaces = 5; 

    return Math.Round(numberToRound, roundingPlaces); 
} 

Как вы можете видеть, теперь у меня есть C# код, который тесно связан с типом в БД. Если мы изменим тип в БД, мы должны будем помнить об изменении этого кода, и это не круто. У меня есть два вопроса:

  1. Есть ли лучший способ?
  2. Если мне нужно поставить эту логику округления в код, имеет ли смысл, чтобы она шла на уровне бизнес-логики или на уровне доступа к данным?
+0

* «Эта точность была бизнес-решением, сделанным заказчиком». * Возможно, это так, что это важное поведение домена не должно быть ответственностью базы данных? – MattDavey

+0

Даже если ответственность не должна быть в БД, нам все равно нужно выбрать количество десятичных знаков для использования, а затем правильно округлить при сохранении в БД. –

+0

То, что я пытался сказать, было, если это поведение домена, правило должно быть закодировано в модель домена в качестве инварианта. Это не имеет ничего общего с схемой базы данных как таковой.Вы намекнули на это в последнем предложении вашего вопроса. – MattDavey

ответ

1

1.Есть ли лучший способ?

Боюсь, что нет. Проблема связана с решением SqlCommand s выполнить параметризованные запросы в качестве удаленного вызова процедур (RPC). Это означает, что он выполняет команду sp_executesql вместо прямой команды SQL (here's, где я получил эту информацию).

Я выяснил, что параметры в sp_executesql всегда усекаются (не округлены) до точности типа данных, с которыми они связаны. Я не знаю, почему, по-видимому, не соответствует присваивание значения с большей точностью до десятичного знака в T-SQL, который вызывает значение округляется:

SET NUMERIC_ROUNDABORT OFF -- is default 
DECLARE @p1 Decimal(16,6) = 32.6607647 
PRINT @p1 
-- result: 32.660765 

Так что я не вижу никакого другого работайте вокруг, чем делать округление самостоятельно. (Кстати, метод по умолчанию округление в .NET является округление банкира. Вы можете использовать MidpointRounding.AwayFromZero.)


2.business логический слой или слой доступа к данным?

По-моему, это так тесно связано с реализацией уровня данных (это может быть не проблема с другими поставщиками баз данных!), Что я бы не допустил, чтобы эта особенность вылилась в бизнес-уровень. Более того, в бизнес-слое вы, вероятно, хотите с максимальной точностью сохранить результаты промежуточных вычислений. Только когда дело доходит до хранения значений, округление приходит в игру.

+0

+1 Мне нравится точка зрения других поставщиков БД, возможно, не имеющих этой проблемы. Я хотел бы согласиться с тем, что это округление принадлежит слою данных, но мои коллеги предложили другое. Вот почему я хотел узнать, что думают другие. Благодаря! –