C# 为tinyint列生成的查询将强制转换为int
我正在查询一个tinyint列,entity framework生成一个SELECT查询,该查询为该列引入转换为INT,即使我在WHERE子句中使用的值是byte类型 查看模型,我的tinyint列生成的类型是byte 查看代码:C# 为tinyint列生成的查询将强制转换为int,c#,sql-server,entity-framework,C#,Sql Server,Entity Framework,我正在查询一个tinyint列,entity framework生成一个SELECT查询,该查询为该列引入转换为INT,即使我在WHERE子句中使用的值是byte类型 查看模型,我的tinyint列生成的类型是byte 查看代码: byte byteValue = 6; var entityList = from r in rep.DataContext.FooTable where r.TinyintColumn == byteValue
byte byteValue = 6;
var entityList = from r in rep.DataContext.FooTable
where r.TinyintColumn == byteValue
select r;
查看生成的查询:
SELECT [Extent1].[TinyintColumn] AS [TinyintColumn] WHERE @p__linq__0 = CAST( [Extent1].[TinyintColumn] AS int)
我在表演上有严格的限制,所以我不想在任何选择中使用这些角色
所以我的问题是,有什么办法可以避免这件事?还是我做错了什么
提前感谢。强制转换将影响性能,因为索引不会用于
TinyintColumn
这是中第2点和第4点的组合。CAST是一个列上的函数,如果没有它,数据类型将不匹配
@p\uu linq\uu 0
应为tinyint或显式强制转换
然而,根据and(SO),LINQ可能不喜欢tinyint主键
你可以“字节”这个项目符号(对不起)并使用smallint…我正在发布我针对这个问题采取的解决方案
EntityFramework4.0似乎总是生成带有强制转换tinyint或smallint字段的查询。因此,为了优化性能,我决定将这些字段改为INT,以避免强制转换,并将其他nvarchar字段的大小从nvarchar(50)改为nvarchar(30)。因此,最后我将行的大小从143字节更改为135字节。我的同事在Entity Framework 4.0上发现了非常好的解决方法。
为smallint工作,我没有试过tinyint 代替equals(=)-使用Contains()运算符,该运算符是用EF 4.0实现的 例如:
假设您拥有SmallIntColumn列。
而不是:
short shortValue = 6;
var entityList = from r in rep.DataContext.FooTable
where r.SmallIntColumn == shortValue
select r;
short shortValue = 6;
var entityList = from r in rep.DataContext.FooTable
where r.SmallIntColumn == shortValue
select r;
使用
检查生成的SQL-现在没有强制转换从我的测试来看,执行计划在列上使用了我的(过滤的)索引,非常完美 希望有帮助。
Shlomi如果Sql表列数据类型为tinyint,则相应的POCO对象应具有byte类型的属性。这对你有用。否则,当您遍历LINQ对象时,它将抛出一个错误,指出无法将字节类型转换为int或您为属性定义的任何类型 我刚刚用EF 4.3代码优先的方法进行了验证,一切都很顺利。如果使用
IList.Contains
和列表,实体框架将不会强制转换
List<byte> byteValue = new List<byte> { 6 };
var entityList = from r in rep.DataContext.FooTable
where byteValue.Contains(r.TinyintColumn)
select r;
List byteValue=新列表{6};
var entityList=来自rep.DataContext.FooTable中的r
其中byteValue.Contains(r.TinyintColumn)
选择r;
我遇到了相同的问题。我在使用带有lambda表达式的EF时遇到了完全相同的问题。将数据类型增强为int不是解决方案,甚至是不好的做法。我发现,正如其他人在这里报告的那样,当您采取更笨拙的方法时,您确实得到了正确的代码,例如:
SomeEntity.FindBy(i=>newlist{1}.Contains(i.TinyintColumn))
但当你遇到其他问题时,你会遇到不止一个要匹配的值。下面将不使用参数化的查询值,而只是将它们内联到查询体中
SomeEntity.FindBy(i=>newlist{1,2}.Contains(i.TinyintColumn))
这在最初的问题上并没有那么糟糕,但仍然不好,因为这意味着数据库必须为您向它抛出的每个值组合编写一个计划,并且由于没有适当的执行时间聚合,性能分析几乎是不可能的。它还有一些在高负载环境中看不到的性能影响
不要让我开始讨论这些行为/反模式对char/nchar数据类型的影响以及它们对索引的影响。在我看来,围绕数据类型系统C#implements集中所有内容既有局限性,也会导致重大问题
我对EF的看法是,对建模良好的表的非常基本的查询被转换为糟糕的SQL代码,EF遵循反模式。鉴于EF开发带来的炒作和增加的复杂性,我认为这不是一件令人印象深刻的事情!我现在不会在这里讨论这个问题,因为那将是一个完全不同的讨论
选择以上任何一种解决方案,但在使用它们之前要知道它们的缺点。也许EF的第10版会在一定程度上解决这个问题,但是我不会屏住呼吸。如果你想保留你可以使用的逻辑。
代码如下
其中(e=>e.Id==i.FixIntCast()
并保持应用程序逻辑不变。尝试更复杂的IntCastFixExtension版本:
namespace System.Linq {
/// <summary>
/// author: Filip Sielimowicz inspired by
/// http://www.entityframework.info/Home/SmallIntProblem
/// </summary>
public static class IntCastFixExtension {
public static IQueryable<T> FixIntCast<T>(this IQueryable<T> q, bool narrowMemberExpr = true, bool narrowConstantExpr = true) {
var visitor = new FixIntCastVisitor() {
narrowConstExpr = narrowConstantExpr,
narrowMembExpr = narrowMemberExpr
};
Expression original = q.Expression;
var expr = visitor.Visit(original);
return q.Provider.CreateQuery<T>(expr);
}
private class FixIntCastVisitor : ExpressionVisitor {
public bool narrowConstExpr;
public bool narrowMembExpr;
protected override Expression VisitBinary(BinaryExpression node) {
bool eq = node.NodeType == ExpressionType.Equal;
bool neq = node.NodeType == ExpressionType.NotEqual;
if (eq || neq) {
var leftUncasted = ReducePossiblyNotNecessaryIntCastExpr(node.Left);
var rightUncasted = ReducePossiblyNotNecessaryIntCastExpr(node.Right);
var rightConst = node.Right as ConstantExpression;
if (leftUncasted == null) {
return base.VisitBinary(node);
}
if (rightUncasted != null) {
if (NarrowTypesAreCompatible(leftUncasted.Type, rightUncasted.Type)) {
// Usuwamy niepotrzebne casty do intów występujące po obu stronach equalsa
return eq ? Expression.Equal(leftUncasted, rightUncasted) : Expression.NotEqual(leftUncasted, rightUncasted);
}
} else if (rightConst != null) {
// Zamiast casta argumentu z lewej w górę do inta (tak zrobił linq2entity)
// zawężamy występującą po prawej stałą typu 'int' do typu argumentu z lewej
if (narrowConstExpr && (rightConst.Type == typeof(int) || rightConst.Type == typeof(int?))) {
var value = rightConst.Value;
var narrowedValue = value == null ? null : Convert.ChangeType(rightConst.Value, leftUncasted.Type);
Expression narrowedConstExpr = Expression.Constant(narrowedValue, leftUncasted.Type);
return eq ? Expression.Equal(leftUncasted, narrowedConstExpr) : Expression.NotEqual(leftUncasted, narrowedConstExpr);
}
} else if (node.Right.NodeType == ExpressionType.MemberAccess) {
// Jak po prawej mamy wyrażenie odwołujące się do zmiennej typu int to robimy podobnie jak przy stałej
// - zawężamy to, zamiast upcasta do inta z lewej.
if (narrowMembExpr) {
var rightMember = node.Right;
var narrowedMemberExpr = Expression.Convert(rightMember, leftUncasted.Type);
return eq ? Expression.Equal(leftUncasted, narrowedMemberExpr) : Expression.NotEqual(leftUncasted, narrowedMemberExpr);
}
}
}
return base.VisitBinary(node);
}
private bool NarrowTypesAreCompatible(Type t1, Type t2) {
if (t1 == typeof(short?)) t1 = typeof(short);
if (t2 == typeof(short?)) t2 = typeof(short);
if (t1 == typeof(byte?)) t1 = typeof(byte);
if (t2 == typeof(byte?)) t2 = typeof(byte);
return t1 == t2;
}
private bool IsNullable(Type t) {
return t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>);
}
private Expression CorrectNullabilityToNewExpression(Expression originalExpr, Expression newExpr) {
if (IsNullable(originalExpr.Type) == IsNullable(newExpr.Type)) {
return newExpr;
} else {
if (IsNullable(originalExpr.Type)) {
Type nullableUncastedType = typeof(Nullable<>).MakeGenericType(newExpr.Type);
return Expression.Convert(newExpr, nullableUncastedType);
} else {
Type notNullableUncastedType = Nullable.GetUnderlyingType(newExpr.Type);
return Expression.Convert(newExpr, notNullableUncastedType);
}
}
}
private Expression ReducePossiblyNotNecessaryIntCastExpr(Expression expr) {
var unnecessaryCast = expr as UnaryExpression;
if (unnecessaryCast == null ||
unnecessaryCast.NodeType != ExpressionType.Convert ||
!(unnecessaryCast.Type == typeof(int) || unnecessaryCast.Type == typeof(int?))
) {
// To nie jest cast na inta, do widzenia
return null;
}
if (
(unnecessaryCast.Operand.Type == typeof(short) || unnecessaryCast.Operand.Type == typeof(byte)
|| unnecessaryCast.Operand.Type == typeof(short?) || unnecessaryCast.Operand.Type == typeof(byte?))
) {
// Jest cast z shorta na inta
return CorrectNullabilityToNewExpression(unnecessaryCast, unnecessaryCast.Operand);
} else {
var innerUnnecessaryCast = unnecessaryCast.Operand as UnaryExpression;
if (innerUnnecessaryCast == null ||
innerUnnecessaryCast.NodeType != ExpressionType.Convert ||
!(innerUnnecessaryCast.Type == typeof(int) || innerUnnecessaryCast.Type == typeof(int?))
) {
// To nie jest podwójny cast między intami (np. int na int?), do widzenia
return null;
}
if (
(innerUnnecessaryCast.Operand.Type == typeof(short) || innerUnnecessaryCast.Operand.Type == typeof(byte)
|| innerUnnecessaryCast.Operand.Type == typeof(short?) || innerUnnecessaryCast.Operand.Type == typeof(byte?))
) {
// Mamy podwójny cast, gdzie w samym środku siedzi short
// Robimy skrócenie, żeby intów nie produkował zamiast short -> int -> int?
// powinno ostatecznie wychodzić short -> short czyli brak castowania w ogóle.
return CorrectNullabilityToNewExpression(unnecessaryCast, innerUnnecessaryCast.Operand);
}
}
return null;
}
}
}
名称空间系统.Linq{
///
///作者:Filip Sielimowicz灵感来源于
/// http://www.entityframework.info/Home/SmallIntProblem
///
公共静态类IntCastFixExtension{
公共静态IQueryable FixIntCast(此IQueryable q,bool-窄带成员expr=true,bool-窄带成员expr=true){
var visitor=new FixIntCastVisitor(){
窄带常数expr=窄带常数expr,
窄带MemberExpr=窄带MemberExpr
};
原始表达式=q.表达式;
var expr=访客访问(原件);
返回q.Provider.CreateQuery(expr);
}
私有类FixIntCastVisitor:ExpressionVisitor{
公共图书馆;
公共图书馆;
受保护的重写表达式访问二进制(BinaryExpression节点){
bool eq=node.NodeType==ExpressionType.Equal;
bool neq=node.NodeType==ExpressionType.NotEqual;
if(eq | | neq){
var leftUncasted=reducePossiblynotnecessaryNTCastXPR(node.Left);
var rightUncasted=reducePossiblynotnecessaryNTCastXPR(node.Right);
var rightcont=节点。右侧为恒常表达式;
short shortValue = 6;
var entityList = from r in rep.DataContext.FooTable
where r.SmallIntColumn == shortValue
select r;
short shortValue = 6;
var entityList = from r in rep.DataContext.FooTable
where r.SmallIntColumn.Equals(shortValue)
select r;