C# 为什么我的EF似乎从正在工作的SQL视图返回重复的行?

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

我已经查过这个问题了,但没有发现对我有用的东西。我在SQL中创建了一个视图,当您在ManagementStudio中运行它时,该视图就会工作。从我的MVC应用程序访问视图时,EF返回的是相同的行,而不是数据不同的行

表格:汽车

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]
  • [加勒比]
查看:CarBookings

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号车
当我从MVC应用程序访问同一视图时,我得到:

  • 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模型,很难想象您仍然会得到重复的模型。根据你提问中的信息,我现在空手了。你可以考虑接受这个解决方案来回答这个问题。你救了我的一天!