C# 为什么我的EF似乎从正在工作的SQL视图返回重复的行?
我已经查过这个问题了,但没有发现对我有用的东西。我在SQL中创建了一个视图,当您在ManagementStudio中运行它时,该视图就会工作。从我的MVC应用程序访问视图时,EF返回的是相同的行,而不是数据不同的行 表格:汽车C# 为什么我的EF似乎从正在工作的SQL视图返回重复的行?,c#,sql,entity-framework,C#,Sql,Entity Framework,我已经查过这个问题了,但没有发现对我有用的东西。我在SQL中创建了一个视图,当您在ManagementStudio中运行它时,该视图就会工作。从我的MVC应用程序访问视图时,EF返回的是相同的行,而不是数据不同的行 表格:汽车 SELECT [C].[Id], [C].[Registration], [C].[Make], [C].[Model], [B].[BookingStartDate], [B].[Book
SELECT [C].[Id],
[C].[Registration],
[C].[Make],
[C].[Model],
[B].[BookingStartDate],
[B].[BookingEndDate]
FROM [Cars] AS C INNER JOIN [Bookings] AS B ON C.Id = B.CarId
public ActionResult GetBookings([DataSourceRequest] DataSourceRequest request)
{
var bookings = unitOfWork.BookingsRepository.Get();
var result = bookings.ToDataSourceResult(request);
return Json(result, JsonRequestBehavior.AllowGet);
}
public DbSet<Bookings> Bookings { get; set; }
private GenericRepository<Bookings> bookingsRepository;
public GenericRepository<Bookings> bookingsRepository
{
get
{
if (this.bookingsRepository == null)
{
this.bookingsRepository = new GenericRepository<Bookings>(context);
}
return bookingsRepository;
}
}
public virtual IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "")
{
IQueryable<TEntity> query = dbSet.AsNoTracking();
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
- [Id]
- [注册]
- [制作]
- [型号]
SELECT [C].[Id],
[C].[Registration],
[C].[Make],
[C].[Model],
[B].[BookingStartDate],
[B].[BookingEndDate]
FROM [Cars] AS C INNER JOIN [Bookings] AS B ON C.Id = B.CarId
public ActionResult GetBookings([DataSourceRequest] DataSourceRequest request)
{
var bookings = unitOfWork.BookingsRepository.Get();
var result = bookings.ToDataSourceResult(request);
return Json(result, JsonRequestBehavior.AllowGet);
}
public DbSet<Bookings> Bookings { get; set; }
private GenericRepository<Bookings> bookingsRepository;
public GenericRepository<Bookings> bookingsRepository
{
get
{
if (this.bookingsRepository == null)
{
this.bookingsRepository = new GenericRepository<Bookings>(context);
}
return bookingsRepository;
}
}
public virtual IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "")
{
IQueryable<TEntity> query = dbSet.AsNoTracking();
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
- [Id]
- [预订开始日期]
- [BookingEndate]
- [加勒比]
SELECT [C].[Id],
[C].[Registration],
[C].[Make],
[C].[Model],
[B].[BookingStartDate],
[B].[BookingEndDate]
FROM [Cars] AS C INNER JOIN [Bookings] AS B ON C.Id = B.CarId
public ActionResult GetBookings([DataSourceRequest] DataSourceRequest request)
{
var bookings = unitOfWork.BookingsRepository.Get();
var result = bookings.ToDataSourceResult(request);
return Json(result, JsonRequestBehavior.AllowGet);
}
public DbSet<Bookings> Bookings { get; set; }
private GenericRepository<Bookings> bookingsRepository;
public GenericRepository<Bookings> bookingsRepository
{
get
{
if (this.bookingsRepository == null)
{
this.bookingsRepository = new GenericRepository<Bookings>(context);
}
return bookingsRepository;
}
}
public virtual IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "")
{
IQueryable<TEntity> query = dbSet.AsNoTracking();
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
如果在SSMS中运行查询,我将获得所有预期结果,例如:
- 2018年3月12日预订的第1辆车
- 2018年9月19日预订的1号车
- 2018年3月12日预订的第1辆车
- 2018年3月12日预订的第1辆车
KendoUI
并将结果返回到网格中
以下是获取数据的控制器代码:
HomeController.cs
SELECT [C].[Id],
[C].[Registration],
[C].[Make],
[C].[Model],
[B].[BookingStartDate],
[B].[BookingEndDate]
FROM [Cars] AS C INNER JOIN [Bookings] AS B ON C.Id = B.CarId
public ActionResult GetBookings([DataSourceRequest] DataSourceRequest request)
{
var bookings = unitOfWork.BookingsRepository.Get();
var result = bookings.ToDataSourceResult(request);
return Json(result, JsonRequestBehavior.AllowGet);
}
public DbSet<Bookings> Bookings { get; set; }
private GenericRepository<Bookings> bookingsRepository;
public GenericRepository<Bookings> bookingsRepository
{
get
{
if (this.bookingsRepository == null)
{
this.bookingsRepository = new GenericRepository<Bookings>(context);
}
return bookingsRepository;
}
}
public virtual IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "")
{
IQueryable<TEntity> query = dbSet.AsNoTracking();
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
我的应用程序使用通用存储库。我不确定这是否是导致问题的原因,但值得一提。下面是从我的存储库中获取的GET
方法
DAL/GenericRepository.cs
public virtual IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "")
{
IQueryable<TEntity> query = dbSet;
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
当我搜索这个问题的答案时,我读到视图没有ID
,因此EF尝试按唯一值对记录进行逻辑排序,这有时会导致问题(来源:)
我根据上面的文章调整了我的视图select
code,但它对我不起作用;我仍然看到重复的:
SELECT ROW_NUMBER() OVER (ORDER BY Car.Id) AS NID,
Car.Id,
Booking.BookingStartDate
... etc...
FROM Cars AS Car INNER JOIN
Booking AS Booking ON Car.Id = Booking.Car_Id
如前所述,如果没有主键,视图可能会变得混乱
通常,您需要为视图上的至少一个属性添加[Key]属性-在EF 1中,edmx设计器最初的建议是将视图上的所有属性都设置为主键,但这可能有些过分。但如果将其添加到一个属性中不起作用,请尝试将其添加到所有属性或属性的子集中,以便每个实体都有一个唯一的键组合,例如
public partial class CarsBookings
{
[Key]
public int Id { get; set; }
[Key]
public string Registration { get; set; }
}
我做了更多的挖掘,除了上面提到的[Key]视图外,我发现的其他线程都指向.AsNoTracking()
,作为一个潜在的解决方案。我对此进行了更多的研究,并试图在我的解决方案中实现这一点
以下是与我的问题相关的评论之一:
AsNoTracking()允许绕过EF中的“每个记录的唯一键”要求(其他答案未明确提及)
这在读取不支持唯一键的视图时非常有用,因为某些字段可能为空,或者视图的性质在逻辑上不可索引
对于这些情况,可以将“key”设置为任何不可为null的列,但必须将AsNoTracking()用于每个查询,否则将跳过记录(按key复制)
资料来源:
在我的GenericRepository.cs
中,我在Get
方法上设置了这个值,我的网格上的结果现在是准确的,没有任何重复
以下是我更改的代码:
GenericRepository.cs
SELECT [C].[Id],
[C].[Registration],
[C].[Make],
[C].[Model],
[B].[BookingStartDate],
[B].[BookingEndDate]
FROM [Cars] AS C INNER JOIN [Bookings] AS B ON C.Id = B.CarId
public ActionResult GetBookings([DataSourceRequest] DataSourceRequest request)
{
var bookings = unitOfWork.BookingsRepository.Get();
var result = bookings.ToDataSourceResult(request);
return Json(result, JsonRequestBehavior.AllowGet);
}
public DbSet<Bookings> Bookings { get; set; }
private GenericRepository<Bookings> bookingsRepository;
public GenericRepository<Bookings> bookingsRepository
{
get
{
if (this.bookingsRepository == null)
{
this.bookingsRepository = new GenericRepository<Bookings>(context);
}
return bookingsRepository;
}
}
public virtual IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "")
{
IQueryable<TEntity> query = dbSet.AsNoTracking();
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
公共虚拟IEnumerable Get(
表达式筛选器=空,
Func orderBy=null,
字符串includeProperties=“”)
{
IQueryable query=dbSet.AsNoTracking();
if(过滤器!=null)
{
query=query.Where(过滤器);
}
foreach(includeProperty.Split中的var includeProperty
(新字符[]{',},StringSplitOptions.RemoveEmptyEntries)
{
query=query.Include(includeProperty);
}
if(orderBy!=null)
{
returnorderby(query.ToList();
}
其他的
{
返回query.ToList();
}
}
这个改变解决了我的问题。希望以后不会有任何不必要的影响:)感谢所有花时间回复的人。您是否为CarsBookings.cs创建了自己的实体类?@Rob是的,我有。它包含与查询中调用的实体相同的实体。@mjwills我无法运行跟踪,因为它是Azure数据库。据我所知,这对他们来说是不可能的。编辑后:如果您也相应地调整了EF模型,很难想象您仍然会得到重复的模型。根据你提问中的信息,我现在空手了。你可以考虑接受这个解决方案来回答这个问题。你救了我的一天!