【问题标题】:Comparing Two models shared data types比较两个模型共享数据类型
【发布时间】:2018-04-03 05:03:39
【问题描述】:

您好,我正在尝试比较来自 2 个模型的两个共享数据类型值:

目标 -

    public int Id { get; set; }
    public DateTime StartDate  { get; set; }
    public  DateTime? EndDate { get; set; }
    public string Type { get; set; }
    public double Level { get; set; }
    public bool Achieved { get; set; }

和 距离:

 public class Distance
{
    public int Id { get; set; }
    public double DistanceRun { get; set; }
    public DateTime _Date { get; set; }
    public String AdditionalComments { get; set; }
}

这是我的代码,用于比较两个日期(目标)之间的距离。

public ActionResult AchievedGoals(string type)
    {
        var goals = db.Goals.Where(x => x.EndDate != null).AsEnumerable();
        List<Distance> distances = new List<Distance>();
        foreach (var goal in goals)
        {
            var goalsBetween = db.Distances.Where(x => x._Date.Date.CompareTo(goal.StartDate) > 0 & x._Date.Date.CompareTo(goal.EndDate) < 0);
            Distance d = (Distance) goalsBetween;
            distances.Add(d);
        }

        return View(distances.ToList());
    }

我收到一个错误

   Distance d = (Distance) goalsBetween;

表示此错误的行

System.InvalidCastException: '无法将'System.Data.Entity.Infrastructure.DbQuery`1[WAD_Tracker.Models.Distance]'类型的对象转换为'WAD_Tracker.Models.Distance'类型。'

这也是视图:

 @model IEnumerable<WAD_Tracker.Models.Goals>

@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Index</h2>

<p>
@Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
    <th>
        @Html.DisplayNameFor(model => model.StartDate)
    </th>
    <th>
        @Html.DisplayNameFor(model => model.EndDate)
    </th>
    <th>
        @Html.DisplayNameFor(model => model.Type)
    </th>
    <th>
        @Html.DisplayNameFor(model => model.Level)
    </th>
    <th>
        @Html.DisplayNameFor(model => model.Achieved)
    </th>
    <th></th>
</tr>

@foreach (var item in Model) {
<tr>
    <td>
        @Html.DisplayFor(modelItem => item.StartDate)
    </td>
    <td>
        @Html.DisplayFor(modelItem => item.EndDate)
    </td>
    <td>
        @Html.DisplayFor(modelItem => item.Type)
    </td>
    <td>
        @Html.DisplayFor(modelItem => item.Level)
    </td>
    <td>
        @Html.DisplayFor(modelItem => item.Achieved)
    </td>
    <td>
        @Html.ActionLink("Edit", "Edit", new { id=item.Id }) |
        @Html.ActionLink("Details", "Details", new { id=item.Id }) |
        @Html.ActionLink("Delete", "Delete", new { id=item.Id })
    </td>
</tr>
}

</table>

【问题讨论】:

  • 您正在尝试将距离集合投射到距离。您可以尝试使用 db.Distances.where(yourcondition).FirstOrDefault() 来获取一行距离

标签: c# asp.net-mvc linq asp.net-mvc-5


【解决方案1】:

错误告诉您问题所在:您不能将DbQuery 转换为Distance。 您当前正在尝试将“准备好的查询”直接投射到对象中。你不能那样做。您需要“执行”查询。尝试改用这一行

var goalsBetween = db.Distances.Where(x => x._Date.Date.CompareTo(goal.StartDate) > 0 & x._Date.Date.CompareTo(goal.EndDate) < 0).FirstOrDefault();

您的代码似乎将多个距离添加到列表中。对你来说,你应该使用.ToList().ToEnumerable() 来“执行”你的查询,而不是如下

var targetsBetween = db.Distances.Where(x => x._Date.Date.CompareTo(goal.StartDate) > 0 & x._Date.Date.CompareTo(goal.EndDate) (距离)g);

最后的select 调用将简单地将列表中的每个项目转换为Distance

然后您可以使用 `addRange" 将它们添加到distances,如下所示:

var goalsBetween = db.Distances.Where(x => x._Date.Date.CompareTo(goal.StartDate) > 0 & x._Date.Date.CompareTo(goal.EndDate) < 0).ToList().Select(g => (Distance)g);
distances.AddRange(goalsBetween);

【讨论】:

    【解决方案2】:

    表达式db.Distances.Where(x =&gt; x._yourWhereClause) 将返回Distance 对象的集合(特别是IQueryable)。但在下一行中,您尝试将其转换为单个 Distance 对象,

     Distance d = (Distance) goalsBetween;
    

    因此您收到错误消息!您不能将集合转换为单个对象。

    您不需要强制转换为单个对象。您应该在 IQueryable 集合上调用 ToList() 方法,这将为您提供一个距离对象列表,并使用 AddRange 方法将该列表添加到 distances 列表中。

    var distanceList= db.Distances
                        .Where(yourWhereClausePredicate)
                       .ToList();
    distances.AddRanges(distanceList);
    

    要在 LINQ 查询中比较 DateTime 属性的 Date 值,您应该使用 DbFunctions.TruncateTime 方法。

    var distanceList= db.Distances
                        .Where(f => DbFunctions.TruncateTime(f._Date) 
                                             <= DbFunctions.TruncateTime(goal.EndDate)
                                    &&  DbFunctions.TruncateTime(f._Date) 
                                             >= DbFunctions.TruncateTime(goal.StartDate)
                              )
                       .ToList();
    distances.AddRanges(distanceList);
    

    请记住,在循环的每次迭代中调用 ToList() 将执行 LINQ 查询(调用数据库)以获取结果。如果您的循环大小很大,我建议您将所有内容读取到本地缓存并进行查询。同样,衡量性能并使用最适合您的情况。

    【讨论】:

    • 使用此方法会收到此错误:System.NotSupportedException: '指定类型成员'日期'在 LINQ to Entities 中不受支持。仅支持初始化程序、实体成员和实体导航属性。'
    • 我在语句中取出了额外的 .Date 并得到了一个新错误: System.NotSupportedException: 'The specified type member 'Date' is not supported in LINQ to Entities。仅支持初始化程序、实体成员和实体导航属性。'
    • 您不能使用 Date 属性在 linq 查询中进行比较。请参阅解决方法的更新答案。
    猜你喜欢
    • 2017-01-24
    • 2019-08-06
    • 1970-01-01
    • 2020-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多