无法使用EF Core将Int转换为Decimal?

时间:2017-02-04 20:15:14

标签: c# mysql entity-framework entity-framework-core

我正试图用MySQL数据库中的Entity Framework Core向ASP.Net中提取大量注入(22位以上)的问题。

EF Core不支持BigInteger以及我收到的建议,而不是decimal。但是,在我的实体上使用decimal类型时,在尝试从数据库中进行选择时,我总是会收到以下异常:

  

System.InvalidCastException:无法转换类型的对象   ' System.Int32'输入' System.Decimal'

在数据库中,列为INT(25),在我的模型中,类型为decimal,这是一个示例模型:

[Table("alliance_reputation_rankings")]
public class AllianceReputationRank
{
    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    [Column("date")]
    public DateTime Date { get; set; }

    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    [Column("world")]
    public int World { get; set; }

    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    [Column("alliance")]
    public string Alliance { get; set; }

    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    [Column("rank")]
    public int Rank { get; set; }

    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    [Column("reputation")]
    public decimal Reputation { get; set; }

    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    [Key]
    [Column("entry_id")]
    public int EntryId { get; set; }
}

我无法使用EF Core选择Reputation属性。即使我尝试在属性之前使用(decimal)来投射它:

选择的粗略示例:

_context.AllianceReputationRankings
   .Where(p => p.Date == rank.Date && p.Alliance== rank.Alliance && p.World == rank.World)
                                   .Select(pl =>  new AllianceReputationRank
                                   {
                                       Date = pl.Date,
                                       World = pl.World,
                                       Alliance = pl.Alliance,
                                       Reputation = (decimal)pl.Reputation
                                   }
                                   ).FirstOrDefault();

如何在模型中使用小数来从数据库中引入大量内容?如果我不能使用小数,我如何在EF Core中使用大数字?

2 个答案:

答案 0 :(得分:1)

我所做的似乎奏效的是乘以1m

context.AllianceReputationRankings
   .Where(p => p.Date == rank.Date && p.Alliance== rank.Alliance && p.World == rank.World)
        .Select(pl =>  new AllianceReputationRank
        {
            Date = pl.Date,
            World = pl.World,
            Alliance = pl.Alliance,
            Reputation = pl.Reputation * 1m
        }
    ).FirstOrDefault();

这似乎允许十进制运算,而不会降低性能。

答案 1 :(得分:0)

实体框架期望数据库和模型之间存在非常紧密类型约束,它实际上不希望看到具有decimal属性的数字列。我在这里列出了几个选项,每个选项都有自己的优点和缺点。随意使用最适合您的一个。

由于您使用的是MySQL,我推荐的第一个选项是您可以将列类型从INT(25)更改为DECIMAL(25, 0)。然后,您应该能够在实体框架中使用decimal,以便尽可能多地使用

如果你做不到,那么,遗憾的是,你处在一个非常紧张的角落里。实体框架核心只是不是这项工作的正确工具,它还不够成熟。在评论中,您澄清了您在数据库中使用此数字列进行数学运算,这意味着stringVARCHAR(25)不在游戏手册中,除非您可以使用该数学 out 的数据库。

此解决方案依赖于此整个模型是只读的假设。如果是(并且需要从Entity Framework Core更新数据库),那么您可以在MySQL中构建一个VIEW,将INT(25)列转换为a VARCHAR(25),并执行以下操作:

[NotMapped]
public BigInteger ReputationValue { get; set; }

public string Reputation
{
    get
    {
        return ReputationValue.ToString();
    }
    set
    {
        ReputationValue = BigInteger.Parse(value);
    }
}

问题在于你无法通过VIEW真正更新数据库,所以如果你想更新这些记录(基本上与整个模型有关),你需要编写手册SQL,或构建存储过程。这只是实体框架核心的一个限制,无法轻易获得

最后,最后一个选项是使用存储过程/方法进行读写。然后,您可以向其传递WHERE子句(如果您想接受构建C#样式转换的挑战,请执行此操作,否则只需添加传递给方法的WHERE sqlConditionCode ...字符串即可过滤东西。

然后构建第二个存储过程/方法来进行更新。您可以调用dbContext.Update(model)将所有内容传递给存储过程进行更新,dbContext.Get("WHERE EntryId = @EntryId", new List<SqlParamter> { new SqlParamter("@EntryId", ...) })我确定您已明白这一点。

类似的东西:

public IEnumerable<AllianceReputationRank> GetAllianceReputationRanks(string whereClause, IEnumerable<MySqlParameter> parameters)
{
    // Get a connection string from somewhere
    var connectionString = string.Empty;

    using (var connection = new MySqlConnection(connectionString))
    using (var command = new MySqlCommand("SELECT * FROM alliance_reputation_rankings " + (whereClause ?? string.Empty), connection))
    {
        connection.Open();

        foreach (var parameter in parameters)
        {
            command.Parameters.Add(parameter);
        }

        using (var reader = command.ExecuteReader())
        {
            if (reader.HasRows)
            {
                // Build a list or use `yield return`, if building a list instance here
                var result = new List<AllianceReputationRank>();

                while (reader.Read())
                {
                    // Build a model of `AllianceReputationRank` here
                    var model = new AllianceReputationRank();

                    // Use reflection or just add each property manually
                    model.Date = reader.GetDate("date");
                    // ...

                    // Make sure you read `reputation` as a string, then `BigInteger.Parse` it to your model
                    model.Reputation = BigInteger.Parse(reader.GetString("reputation"));

                    // Either add the model to the list or `yield return model`
                    result.Add(model);
                }

                // If you built a list then `return` it
                return result;
            }
        }
    }
}

建立相反的方法恰恰相反。 ?? string.Empty可能是多余的,我不会在我面前设置一个IDE,以检查string + null是否会引发异常,但如果您不喜欢它,则可以删除它。 (在我看来,这比对不起更安全。)我真的希望我的所有类型和用法都是正确的,如果没有,我为除了添加连接字符串和其他属性之外的任何修改道歉。

老实说,DECIMAL(25, 0)选项应该对你有用,如果那不存在那么存储过程/方法选项应该。两者都应该将数学保留在数据库中,并希望在破坏实体框架核心问题的同时不破坏任何其他内容。是不理想?当然,我希望它不是必要的。但是,不幸的是,实体框架核心非常新,并且仍然需要大量更新才能添加Entity Framework not-Core所具有的简单功能。 (例如Like the lack of a .Find method in Entity Framework Core。)

我希望我们有更好的消息,但是没有能力构建我们自己的可映射类型(即构建我们自己的实体框架核心支持的BigInteger)只有 isn&#t; t < / em>要解决这个问题还有很多工作要做,我们会坚持使用恶劣的解决办法让它做我们需要的工作。