我想用实体框架做这样的工作:
db.Customers.OrderBy(c => c.MoneySpent/c.OrdersPlaced)
不必像以下那样对零保护进行任何划分:
db.Customers.OrderBy(c => c.OrdersPlaced == 0 ? 0.0 : c.MoneySpent/c.OrdersPlaced)
为了做到这一点,我尝试了几件事,但我最接近解决问题的方法是禁用ARITHABORT
和ANSI_WARNINGS
,这是我在上下文的构造函数中所做的:< / p>
public class DatabaseContext : DbContext
{
static DatabaseContext()
{
Database.SetInitializer<DatabaseContext>(null);
}
public DatabaseContext()
: base("Name=DatabaseContext")
{
Database.ExecuteSqlCommand("SET ANSI_DEFAULTS OFF");
Database.ExecuteSqlCommand("SET ARITHABORT OFF");
Database.ExecuteSqlCommand("SET ANSI_WARNINGS OFF");
}
// Tables that can be queried directly
public DbSet<Customer> Customers { get; set; }
}
当我尝试从我的Web API控制器获取结果时,我仍然收到以下错误:
...failed to serialize the response body for content type 'application/json...
InnerException: Divide by zero error encountered...
当我看看SQL Server Profiler发生了什么时,似乎ANSI_WARNINGS
每当发出新查询时都会重置为ON
。
有没有办法可以更改ANSI_WARNINGS
的默认值,使其在查询之间保持OFF
?
答案 0 :(得分:2)
我认为您的问题是ARITHABORT
和ANSI_WARNINGS
命令的范围仅限于交易。
默认情况下,从EF6
Database.ExecuteSqlCommand()
开始将换行 事务中的命令(如果尚未存在)
您必须设置数据库默认值 - (并接受可能具有的所有含义!)
您可以使用sp_configure的用户选项选项来设置默认值 为服务器的所有连接设置ANSI_WARNINGS。更多 信息,see sp_configure (Transact-SQL)。
或者您必须使用EF6的improved transaction support
管理您自己的连接/交易无论哪种方式,要避免编码除以零似乎要做很多工作....
参考文献:
答案 1 :(得分:1)
凭借科林的出色答案,我能够实现以下控制器,现在它完美无缺!谢谢!
public class CustomersController : ApiController
{
private readonly CutomerContext _context = new CustomerContext();
private DbContextTransaction _transactionContext;
public IEnumerable<Customer> Get()
{
_transactionContext = _context.Database.BeginTransaction();
_context.Database.ExecuteSqlCommand("SET ANSI_WARNINGS OFF");
_context.Database.ExecuteSqlCommand("SET ARITHABORT OFF");
var orderedCustomers = _context.Customers.OrderByDescending(c => ((double)c.MoneySpent)/c.OrdersPlaced);
return orderedCustomers.AsEnumerable();
}
protected override void Dispose(bool disposing)
{
_context.Dispose();
if(_transactionContext != null)
_transactionContext.Dispose();
}
}
答案 2 :(得分:0)
您在每个查询中看到重置设置的原因可能与EF默认打开并关闭每个查询的连接这一事实有关。您可以通过手动打开连接来覆盖该行为。
无论如何,我同意这听起来不像是一种强有力的方法。
更好的处理方法可能是确保OrdersPlaced为NULL而不是零(x / NULL不会导致错误但会评估为NULL)。