asp.net-mvc – 实体框架包含OrderBy随机生成重复数据
|
当我从包含一些孩子(通过.Include)的数据库中检索到一个项目列表,并且随机订购时,EF给我一个意想不到的结果..我创建/克隆添加项目.. 为了更好地解释自己,我创建了一个简单的EF CodeFirst项目来重现问题。 该项目 创建一个基本的MVC3项目,并通过Nuget添加EntityFramework.SqlServerCompact包。 > EntityFramework v4.3.0 模型和DbContext using System.Collections.Generic;
using System.Data.Entity;
namespace RandomWithInclude.Models
{
public class PeopleContext : DbContext
{
public DbSet<Person> Persons { get; set; }
public DbSet<Address> Addresses { get; set; }
}
public class Person
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
}
public class Address
{
public int ID { get; set; }
public string AdressLine { get; set; }
public virtual Person Person { get; set; }
}
}
数据库设置和种子数据:EF.SqlServerCompact.cs using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using RandomWithInclude.Models;
[assembly: WebActivator.PreApplicationStartMethod(typeof(RandomWithInclude.App_Start.EF),"Start")]
namespace RandomWithInclude.App_Start
{
public static class EF
{
public static void Start()
{
Database.DefaultConnectionFactory = new SqlCeConnectionFactory("System.Data.SqlServerCe.4.0");
Database.SetInitializer(new DbInitializer());
}
}
public class DbInitializer : DropCreateDatabaseAlways<PeopleContext>
{
protected override void Seed(PeopleContext context)
{
var address1 = new Address {AdressLine = "Street 1,City 1"};
var address2 = new Address {AdressLine = "Street 2,City 2"};
var address3 = new Address {AdressLine = "Street 3,City 3"};
var address4 = new Address {AdressLine = "Street 4,City 4"};
var address5 = new Address {AdressLine = "Street 5,City 5"};
context.Addresses.Add(address1);
context.Addresses.Add(address2);
context.Addresses.Add(address3);
context.Addresses.Add(address4);
context.Addresses.Add(address5);
var person1 = new Person {Name = "Person 1",Addresses = new List<Address> {address1,address2}};
var person2 = new Person {Name = "Person 2",Addresses = new List<Address> {address3}};
var person3 = new Person {Name = "Person 3",Addresses = new List<Address> {address4,address5}};
context.Persons.Add(person1);
context.Persons.Add(person2);
context.Persons.Add(person3);
}
}
}
控制器:HomeController.cs using System;
using System.Data.Entity;
using System.Linq;
using System.Web.Mvc;
using RandomWithInclude.Models;
namespace RandomWithInclude.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
var db = new PeopleContext();
var persons = db.Persons
.Include(p => p.Addresses)
.OrderBy(p => Guid.NewGuid());
return View(persons.ToList());
}
}
}
视图:Index.cshtml @using RandomWithInclude.Models
@model IList<Person>
<ul>
@foreach (var person in Model)
{
<li>
@person.Name
</li>
}
</ul>
这应该是全部,你的应用程序应该编译:) 问题 你可以看到,我们有2个简单的模型(个人和地址),而人可以有多个地址。 结果,我有时会得到4个人,有时5个,有时3个,我期望3.总是。 >人1 所以..它的复制/克隆数据!这不是很酷.. 生成的SQL查询是这样的: SELECT
[Project1].[ID] AS [ID],[Project1].[Name] AS [Name],[Project1].[C2] AS [C1],[Project1].[ID1] AS [ID1],[Project1].[AdressLine] AS [AdressLine],[Project1].[Person_ID] AS [Person_ID]
FROM ( SELECT
NEWID() AS [C1],[Extent1].[ID] AS [ID],[Extent1].[Name] AS [Name],[Extent2].[ID] AS [ID1],[Extent2].[AdressLine] AS [AdressLine],[Extent2].[Person_ID] AS [Person_ID],CASE WHEN ([Extent2].[ID] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C2]
FROM [People] AS [Extent1]
LEFT OUTER JOIN [Addresses] AS [Extent2] ON [Extent1].[ID] = [Extent2].[Person_ID]
) AS [Project1]
ORDER BY [Project1].[C1] ASC,[Project1].[ID] ASC,[Project1].[C2] ASC
解决方法 >如果我从查询中删除.Include(p => p.Addresses),一切顺利。但是当然地址没有加载,并且访问该集合将每次都对数据库进行新的调用。 有没有人知道为什么会这样发生? 解决方法可以通过阅读 AakashM answer和 Nicolae Dascalu answer来排序,似乎Linq OrderBy需要一个稳定的排名功能,NewID / Guid.NewGuid不是。所以我们必须使用一个在单个查询中稳定的随机生成器。 为了实现这一点,在每次查询之前使用.Net随机生成器来获取随机数。然后将该随机数与实体的唯一属性相结合,以便随机排序。为了’随机化’一些结果,校验和。 (校验和是计算哈希的SQL Server函数;创建于this blog的原始构想) 假设Person Id是一个int,你可以这样写你的查询: var rnd = (new Random()).NextDouble();
var persons = db.Persons
.Include(p => p.Addresses)
.OrderBy(p => SqlFunctions.Checksum(p.Id * rnd))
// Uniqueness of ordering ranking must be ensured.
.ThenBy(p => p.Id);
像NewGuid黑客一样,这很可能不是一个很好的随机发生器,具有良好的分布等等。但它并不会导致实体在结果中重复。 编辑:如果您的查询排序不保证您的实体排名的唯一性,您必须补充它以保证它,因此我添加了ThenBy。 旁注:我宁愿使用.Next()方法来获取一个int,然后将它通过一个xor(^)组合到一个实体int unique属性,而不是使用double和乘法。但是SqlFunctions.Checksum不幸的是不提供int数据类型的重载,尽管SQL Server函数应该支持它。你可以用演员克服这个,但是为了保持简单,我终于选择了乘法。 (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- asp.net-mvc – ASP.NET MVC从数据库加载Razor视图
- ASP.Net下载大文件的实现方法
- asp.net – VS2015为Class Library添加引用
- ASP.NET Azure中的Trace.WriteLine
- asp.net – 从VS2008发布的等效msbuild命令
- asp.net-core – ASP.NET Core App中project.json中的build
- asp.net – AspNetSynchronizationContext
- 准备ASP.Net网站进行渗透测试
- asp.net – System.Web.Cache,会话级别或应用程序级别
- asp.net-mvc-4 – 如何在mvc4 ActionLink中加密查询字符串I
- asp.net-mvc – 如何在Visual Studio 2015中快速
- asp.net – 如何绑定DropDownList的选定值
- asp.net – 实体框架:如何解决“FOREIGN KEY约束
- VS 2015 Update 2 – 调试时不存在变量,为什么?
- 为什么在手动刷新响应时ASP.NET将使用Transfer-E
- asp.net-mvc – ASP.NET MVC快速启动 – 一站式教
- asp.net – Visual Studio 2010和Visual Studio
- ASP.NET MVC,ActionFilters,静态类和传递数据
- asp.net – 在Azure Web App中设置EF连接字符串
- asp.net-mvc – ASP.NET MVC:如何绑定List类型的
