在 LINQ 查询中的 Group Join 中将字符串转换为十进制数

9
我需要连接两个表格,但只返回第二个表格中与第一个表格记录相关联的所有记录的“值”的总和相同的记录。
from p in db.TPs
join n in db.TNs
on p.Key equals n.Key
where (decimal.Parse(p.Value) == db.TNs.Where( nn => nn.Key == p.Key )
                                       .Sum( nn=> decimal.Parse(kk.Value)))

我正在使用Entity Framework Code-First。

当然,Linq会抱怨:

LINQ to Entities不支持方法'System.Decimal Parse(System.String)'。

表格很大,我必须减少输出,所以在客户端进行此转换是不可能的。列类型转换也不是一个选择。

SQL查询语句为:

select * from TP as p
join * from TN as n on n.Key = p.Key
where p.Value = (select sum(cast(n.Value as decimal(12,2))) from TN where Key = p.Key)

@YograjGupta - 为什么这会有帮助呢?SQL Server也不知道Convert - Oded
1
因为当您使用Convert.ToDecimal时,它会生成类似于CONVERT(Decimal(29,4),[t0].[value])的SQL语句,所以请尝试这样做。 - Yograj Gupta
也许这个答案可以帮到你:在EF 4中将字符串转换为整数 - Brad Rem
@majkinetor,它正在工作,我使用这个linq进行测试:from x in db.TestStringToDecimals select new { x.Id, val= Convert.ToDecimal(x.Value)},它为我生成了SQL语句:SELECT [t0].[id] AS [Id], CONVERT(Decimal(29,4),[t0].[value]) AS [val] FROM [TestStringToDecimal] AS [t0] - Yograj Gupta
我得到了这个:base {System.SystemException} = {"LINQ to Entities 不认识 'System.Decimal ToDecimal(System.String)' 方法,而且这个方法无法被转换成存储表达式。"} - majkinetor
显示剩余3条评论
3个回答

10

你可以通过创建一些模型定义函数来实现此操作。请参见此链接:在至少使用 Entity Framework 4 中创建和调用模型定义函数

具体来说,要添加将字符串转换为十进制数和整数的函数,请按照以下步骤进行:

以 XML 格式打开 .EDMX 文件,以便您可以编辑文本。

将自定义转换函数添加到“CSDL 内容”部分的“架构”部分。

<edmx:ConceptualModels>
<Schema....>

新增函数:

<Function Name="ConvertToInt32" ReturnType="Edm.Int32">
  <Parameter Name="myStr" Type="Edm.String" />
  <DefiningExpression>
    CAST(myStr AS Edm.Int32)
  </DefiningExpression>
</Function>
<Function Name="ConvertToDecimal" ReturnType="Edm.Decimal">
  <Parameter Name="myStr" Type="Edm.String" />
  <DefiningExpression>
    CAST(myStr AS Edm.Decimal(12, 2))
  </DefiningExpression>
</Function>

根据您的需要修改上述Edm.Decimal的精度。

然后,在您的C#代码中,您需要创建相应的静态方法,并将其存储在静态类中:

// NOTE: Change the "EFTestDBModel" namespace to the name of your model
[System.Data.Objects.DataClasses.EdmFunction("EFTestDBModel", "ConvertToInt32")]
public static int ConvertToInt32(string myStr)
{
    throw new NotSupportedException("Direct calls are not supported.");
}

// NOTE: Change the "EFTestDBModel" namespace to the name of your model
[System.Data.Objects.DataClasses.EdmFunction("EFTestDBModel", "ConvertToDecimal")]
public static decimal ConvertToDecimal(string myStr)
{
    throw new NotSupportedException("Direct calls are not supported.");
}

最后,要调用你的新方法:

using (var ctx = new EFTestDBEntities())
{
    var results = from x in ctx.MyTables
                  let TheTotal = ctx.MyTables.Sum(y => ConvertToDecimal(y.Price))
                  select new
                  {
                      ID = x.ID,
                      // the following three values are stored as strings in DB
                      Price = ConvertToDecimal(x.Price),
                      Quantity = ConvertToInt32(x.Quantity),
                      Amount = x.Amount,
                      TheTotal
                  };
}

你的具体示例将如下所示:

from p in db.TPs
join n in db.TNs
on p.Key equals n.Key
where (ConvertToDecimal(p.Value) == 
        db.TNs.Where( nn => nn.Key == p.Key ).Sum( nn=> ConvertToDecimal(kk.Value)))

@ majkinetor,如果您正在使用Code First,为什么不在代码中首先将数据库字段生成为十进制数? - Brad Rem
现有的数据库。你的意思是,如果我无论如何设置它,Code First都会自动转换吗? - majkinetor
@majkinetor,我不这么认为。虽然我对使用Code First与现有数据库中的EF并不是很熟悉,但你可以看看Entity Framework Power Tools,看看是否有一些工具可以让你的工作更轻松。 - Brad Rem
我不知道为什么EF团队还没有在框架中实现这个,因为解决方案是如此简单。感谢提供代码。 - Adam

0

很遗憾,LINQ to SQL无法创建带有字符串转换为十进制的SQL表达式。

如果您想要这样做,您必须使用以下方法执行自己的查询:

ExecuteStoredQuery


嗯...一些框架...问题在于失去了便利性。我正在创建匿名结果,而ExecuteStoredQuery期望类型。 - majkinetor

0

与其将 string 转换为 decimal,不如将 decimal 转换为 string。 如果其他方法不起作用,这种方法也可以奏效。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接