[英]IQueryable - Why does this logic fail?
我有一个包含多个表的数据库,在这种情况下,相关的表是
志愿者注册和计划事件:
CREATE TABLE [dbo].[VolunteerSignups] (
[EventId] INT IDENTITY (1, 1) NOT NULL,
[VolunteerNum] INT NOT NULL,
[UserId] NVARCHAR (128) NULL,
CONSTRAINT [PK_dbo.VolunteerSignups] PRIMARY KEY CLUSTERED ([EventId] ASC, [VolunteerNum] ASC),
CONSTRAINT [FK_VolunteerSignups_ProgramEvents_UserId] FOREIGN KEY ([UserId]) REFERENCES [dbo].[AspNetUsers] ([Id]) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT [FK_VolunteerSignups_ProgramEvents_EventId] FOREIGN KEY ([EventId]) REFERENCES [dbo].[ProgramEvents] ([EventId])
);
--Triggers and other unneeded info
CREATE TABLE [dbo].[ProgramEvents] (
[EventId] INT IDENTITY (1, 1) NOT NULL,
[EventTitle] NVARCHAR (256) NOT NULL,
[NumVolunteers] INT NOT NULL,
[EventLocation] NVARCHAR (512) NOT NULL,
[ServiceDescription] NVARCHAR (MAX) NOT NULL,
[StartTime] DATETIME NOT NULL,
[EndTime] DATETIME NOT NULL,
CONSTRAINT [PK_dbo.ProgramEvents] PRIMARY KEY CLUSTERED ([EventId] ASC)
);
--Triggers and other unneeded info
总的来说,我所拥有的是一个简单的Web应用程序,它允许进行活动(每个活动可能需要1到N名志愿者),并且志愿者可以报名参加这些活动。 当然,限制是志愿者不能两次报名参加同一活动,并且他们不能报名参加重叠(按时间)的活动。
我几乎完成了MVC应用程序中的所有其他工作,除了志愿者位置要求的后半部分。 我对此有些挣扎,感到恼火,所以我把它留在了最后,而不是让它延迟了整个项目。 但是现在我不能再拖延了,因为除此查询外,其他所有方法都有效。
到目前为止,我有:
[Authorize( Roles = "Administrator, Volunteer" )]
public class VolunteerSignupsController : Controller
{
private EntitiesDb db = new EntitiesDb();
// GET: VolunteerSignups
public async Task<ActionResult> Index()
{
var uid = User.Identity.GetUserId();
var exclude = ( db.VolunteerSignups.Where( o => o.UserId == uid ) );
var volunteerSignups = db.VolunteerSignups.Include( v => v.AspNetUser ).Include( v => v.ProgramEvent );
var diff = volunteerSignups.Where( u => ( !exclude.Any( p => p.EventId == u.EventId ) ) && u.UserId == null );
return View( await diff.ToListAsync() );
}
此代码可以完美地检索用户尚未注册的事件。 问题在于,它们在注册事件后会返回重叠事件。 因此,我将代码修改为以下内容:
[Authorize( Roles = "Administrator, Volunteer" )]
public class VolunteerSignupsController : Controller
{
private EntitiesDb db = new EntitiesDb();
// GET: VolunteerSignups
public async Task<ActionResult> Index()
{
ApplicationDbContext db1 = new ApplicationDbContext();
var uid = User.Identity.GetUserId();
var exclude = ( db.VolunteerSignups.Where( o => o.UserId == uid ) );
var volunteerSignups = db.VolunteerSignups.Include( v => v.AspNetUser ).Include( v => v.ProgramEvent );
var diff = volunteerSignups.Where( u => ( !exclude.Any( p => p.EventId == u.EventId ) ) && u.UserId == null );
//GET: ProgramEvents that user has already signed up for
var alreadyVolunteeredFor = db.ProgramEvents.Where( i => exclude.Any( u => i.EventId == u.EventId ) );
//GET: ProgramEvents that the user has not signed up for
var qualifiesFor = db.ProgramEvents.Where( i => diff.Any( u => i.EventId == u.EventId ) );
/*Get: VolunteerSignups where the ProgramEvent is one where:
-The user has not previously volunteered
-The user has not previously volunteered for a different event where the time overlaps with an event they have not signed up for*/
var intersect = db.VolunteerSignups.Where( i => ( diff.Any( d => ( d.EventId == i.EventId ) &&
!qualifiesFor.Any( q => q.EventId == i.EventId &&
alreadyVolunteeredFor.Any( a => a.EventId == i.EventId &&
a.EndTime.CompareTo( q.StartTime ) >= 0 &&
a.StartTime.CompareTo( q.EndTime ) <= 0 ) ) ) ) );
return View( await intersect.ToListAsync() );
}
我很确定逻辑失败在于构成intersect
的lambda表达式。 在编写过程中,它只返回diff
之前所做的完全相同的事情。 但是,我对此所做的任何更改似乎都从列表中删除了所有内容。
编辑以回复mjwillis评论:
diff
的数据将是VolunteerSignups
行,这些行不会为用户未自愿参与的事件填充。 列是
1. xyz 1 null
2. xyz 2 null
3. abc 1 null
qualifiesFor
应与ProgramEvents
具有相同的行EventId
作为条目diff
:
1. xyz "First Title" 2 "Some Location" "A Description" "11/1/2020 4:00pm" "11/1/2020 7:00pm"
2. abc "Second Title" 1 "A Location" "Some Description" "11/1/2020 5:00pm" "11/1/2020 6:00pm"
alreadyVonteeredFor
应符合ProgramEvents
排人已自愿参加,没有任何的EventId
列应该等于海誓山盟,也不应该是如果任何diff
或qualifiesFor
:
dsd "Already Volunteered" 1 "Some Place" "Time overlaps" "11/1/2020 3:00pm" "11/1/2020 4:30pm"
我需要的是intersect
仅包含diff
行3,因为第1行和第2行对应于时间与志愿者已附着的事件重叠的事件。
我找到了解决方案。 问题在于intersect
lambda中的a => a.EventId == i.EventId &&
。 那是胡说八道,我也不知道为什么会在那儿。 在没有alreadyVolunteeredFor
将是qualifiesFor
和没有的EventId
列将是它的。
正确的答案最终是将intersect
的声明更改为:
var intersect = db.VolunteerSignups.Where( i => ( diff.Any( d => ( d.EventId == i.EventId ) &&
qualifiesFor.Any( q => q.EventId == i.EventId &&
!alreadyVolunteeredFor.Any( a =>
(a.EndTime.CompareTo( q.StartTime ) >= 0) &&
(a.StartTime.CompareTo( q.EndTime ) <= 0 ) ) ) ) ) );
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.