C# 使用Linq读取字节[]或浮点到实体

C# 使用Linq读取字节[]或浮点到实体,c#,entity-framework,linq,asp.net-web-api,C#,Entity Framework,Linq,Asp.net Web Api,我有一个表,一列是二进制的,另一列是浮点的。我需要使用SQL选择以下内容 SELECT ISNULL(myBinary, myFloat) FROM table 这是可行的,我得到了一个包含所有二进制的列 0x3F800000 0xE5C13DBAB611123B47A7 0x9946C3BA9946C3BA9946 0xDE0E1D3C8B7A143C6DB7 0x3F800000 等等 现在我想使用LINQtoEntities进行这个查询,但是我找不到可以编译的代码 context.ta

我有一个表,一列是二进制的,另一列是浮点的。我需要使用SQL选择以下内容

SELECT ISNULL(myBinary, myFloat) FROM table
这是可行的,我得到了一个包含所有二进制的列

0x3F800000
0xE5C13DBAB611123B47A7
0x9946C3BA9946C3BA9946
0xDE0E1D3C8B7A143C6DB7
0x3F800000
等等

现在我想使用LINQtoEntities进行这个查询,但是我找不到可以编译的代码

context.table.select(s => new MyObject()
  { 
     Result = s.myBinary ?? s.myFloat // <--- '??' operator cannot be applied to operands of type 'byte[]' and 'float'
  });

 class MyObject { public Object Result {get; set;} }
收益率(即使多次执行,也总是差不多)

注:我在一篇评论中写了因子40,这是另一种测量方法。统计时间的结果约为因子10

如果我增加行的数量,我得到

(50000 rows affected)

 SQL Server Execution Times:
   CPU time = 47 ms,  elapsed time = 820 ms. (with ISNULL)

(50000 rows affected)

 SQL Server Execution Times:
   CPU time = 16 ms,  elapsed time = 1365 ms.

对于更少的行(大约1000或更少),执行时间是不可测量的,所以大约1毫秒。但是:我预计每个查询大约5000到10000行

您试图让它工作的方式的问题是,您需要借助一些讨厌的黑客来确定您的返回值是
字节[]
还是
浮点值
。这就是为什么您一直试图让EF查询返回
对象
。通过将
float
破解成
字节[]
,可以让它工作,但我建议一种更简单、更合乎逻辑的方法:返回两个值,让应用程序决定做什么。例如,返回类似以下对象的内容:

public class FloatOrByte // Do not call it this!
{
    public byte[] MyBinary { get; set; }
    public float MyFloat { get; set; }
}
然后像这样返回:

var result = context.table.Select(s => new FloatOrByte
{ 
    MyBinary = s.myBinary,
    MyFloat = s.myFloat
};
现在可以检查空值:

if(result.MyBinary != null)
{
    // Do stuff with the byte value
}
else
{
    // Do stuff with the float value
}

请更改类定义以接受空值

public class FloatOrByte 
{
    public byte[] MyBinary { get; set; }
    public float? MyFloat { get; set; }
}
然后使用DBContext类获取值。问题是EF无法将空合并运算符转换为SQL

var result = context.table.Select(s => s);

var processResult = result.Tolist().Select(s=> new MyObject{

    Result = (s.MyBinary == null) ? (object)s.MyFloat : (object)s.MyBinary 

 });

作为解决方案,我可以提供一个自定义存储函数,映射到内置的
ISNULL
SQL函数

若您使用的是代码优先模型,那个么您将需要一个包

但由于您使用的是edmx,因此该过程有点复杂,需要手动编辑edmx文件。MSDN主题部分介绍了该技术

使用XML(文本)编辑器打开edmx文件。找到
edmx:StorageModels
元素的
Schema
子元素,并在其中添加以下内容:

<Function Name="IsNull" BuiltIn="true" IsComposable="true" ReturnType="binary">
  <Parameter Name="expr1" Type="binary" />
  <Parameter Name="expr2" Type="float" />
</Function>
(更新
名称空间
字符串以匹配
元素的
名称空间
属性的值)

就这些。现在,您应该能够在LINQ to Entities查询中使用上述函数:

class MyObject { public byte[] Result { get; set;} }

context.MyTable.Select(e => new MyObject
{ 
    Result = CustomDbFunctions.IsNull(e.myBinary, e.myFloat)
});

EF6将很高兴地将其转换为所需的SQL
ISNULL
函数。

是否尝试强制转换?e、 g.
Result=(对象)s.myBinary??(对象)s.myFloat
。我同意DavidG的观点-你可能不应该这样做。你希望你的应用程序如何处理
浮动
字节[]
?你只剩下一些可怕的事情,比如反射。为什么不返回两个值并使用二进制列,除非它为null?嗯。。。我无法将类型“System.Byte[]”转换为类型“System.Object”。LINQ to实体仅支持强制转换EDM基元或枚举类型。@DavidG性能有问题。阅读两者都会产生过多的流量。浮点值总是被读取,并且总是不为空。但我只需要在二进制项为null的情况下才需要它。可能的解决方案是:创建一个视图,执行
从表中选择ISNULL(myBinary,myFloat)并将其映射到EFYes,我现在已经实现了它,但这会使代码太慢。在op中执行SQL显然比返回两列都要快。真的有性能问题吗?诚然,它并不完美,但我怀疑返回一个并不总是需要的浮点值是否会影响你的应用程序,特别是当你返回一个可能非常大的
字节[]
时。嗯,我真的不知道,因为我还没有让代码工作。然而,只有在SQL Server Manager中工作,我才能获得性能。使用opsql进行boost。是的,现在对客户来说速度太慢了。您如何通过使用SQL Server Manager判断性能提升?这对我来说没有意义。请确定执行一个SQL查询的时间与执行另一个SQL查询的时间的范围。引号:运算符“??”不能应用于“byte[]”和“float”类型的操作数请阅读OP的注释:“无法将“System.byte[]”类型强制转换为“System.Object”类型”任何类型都可以转换为对象类型,即使是用户定义的类型。我希望您有一个对象类型为“Result”属性的类MyObject,它在我的代码中工作得很好。请尝试错误消息:无法将类型“System.Single”强制转换为类型“System.Object”。LINQtoEntities只支持强制转换EDM基元或枚举类型。我对它进行了测试,它看起来工作得很好。。。给我几个小时,我会用真实的生产数据再检查一遍
<Function Name="IsNull" BuiltIn="true" IsComposable="true" ReturnType="binary">
  <Parameter Name="expr1" Type="binary" />
  <Parameter Name="expr2" Type="float" />
</Function>
public static class CustomDbFunctions
{
    const string Namespace = "EFTest.MyDbContextModel.Store";

    [DbFunction(Namespace, "IsNull")]
    public static byte[] IsNull(byte[] expr1, double expr2) => throw new NotSupportedException();
}
class MyObject { public byte[] Result { get; set;} }

context.MyTable.Select(e => new MyObject
{ 
    Result = CustomDbFunctions.IsNull(e.myBinary, e.myFloat)
});