我申请志愿者申请仪式。
他们查找可用的仪式列表,只需单击“连接”即可创建关系。
但是,如果这个仪式是其中的一部分,我希望将这个仪式从列表中删除。
这是我在控制器中的行动:
public ActionResult ViewAvailableCeremonies()
{
string username = Membership.GetUser().UserName;
var getVolunteer = (from vol in db.Volunteers
where username == vol.Username
select vol).SingleOrDefault();
var ceremonies = (from a in getVolunteer.Appointments
where a.Fee != null
&& a.Slots != 0
//&& getVolunteer.Appointments.Any(c => a.)
select a).ToList();
return View(ceremonies);
}
我一直在想着如何解决这个问题,但我的大脑却完全被炒了。我知道我需要查询列表以检查它们是否在那里。
一如既往,感谢您的帮助
答案 0 :(得分:0)
您似乎根据用户约会过滤了可用的cerimonies。
首先,你必须搜索所有的cerimonies:
<强> E.G。强>
var ceremonies = (from a in db.Cerimonies
select a).ToList();
因此,您根据用户约会过滤了cerimonies:
我假设您在Ceremony和Appointment之间有关系,其中Appointment类中的外键是CerimonyID,而Ceremony类中的主键是ID
<强> E.G。强>
string username = Membership.GetUser().UserName;
var getVolunteer = (from vol in db.Volunteers
where username == vol.Username
select vol).SingleOrDefault();
var userAppointmentsIds = (from a in getVolunteer.Appointments
where a.Fee != null &&
a.Slots != 0
select a.CerimonyID).ToList();
var filteredCerimonies = ceremonies
.Where(c => !userAppointmentsIds.Contain(c.ID))
.ToList();
答案 1 :(得分:0)
因此,在您的应用程序中,您有Volunteer
,希望通过其唯一身份标识来识别,或者如果必须使用非唯一用户名。
在此应用程序中,您希望显示此志愿者尚未参加的所有仪式的列表。
在您的示例代码中,我看到了一些完全不同的东西。我看到约会(约会与仪式一样吗?)显然有一个要求是不要使用所有的约会,但是有非零费用和非零转换的东西,
除此之外,我发现您不止一次访问您的数据库(或您的表),这实际上并不高效。
出于效率原因:尽量保持LINQ语句IEnumerable / IQueryable,只有当你需要最终结果时才使用ToList / ToDictionary / SingleOrDefault / FirstOrDefault / Any等
LINQ语句的连接很快。它只是改变枚举序列所需的表达式。缓慢的部分是在ToList / Any / etc。
中开始枚举说完这个。我不确定您是否使用实体框架来访问您的数据库。如果是这样,你的答案很容易。见结尾。
因此,为了识别您的志愿者,您有一个独特的volunteerId,
或者如果没有可用的(公平)唯一userName
。
您还有一系列Volunteers
和一系列Ceremonies
(Appointments
,其中包含非空Fee
和非零Slots
。
Volunteers
和Appointments
之间存在多对多关系:每个Volunteer
可以有零个或多个Appointments
;每个Appointment
都有零个或多个Volunteers
。
在数据库中,这是使用联结表实现的,让我们调用此表VolunteersAppointments
。
好的,我们已经正确定义了您的问题。以下是课程:
class Volunteer
{
public int Id {get; set;}
public string UserName {get; set;}
...
}
class Appointment
{
public int Id {get; set}
public <someType1> Fee {get; set;}
public <someType2> Slots {get; set;}
...
}
// junction table
class VolunteersAppointments
{
public int UserId {get; set;}
public int AppointmentId {get; set;}
}
可能是你以不同的方式定义了你的课程,但你得到了要点。
要获得所有仪式,使用UserName的用户尚未参加:
string userName = ...
IQueryable<Volunteer> volunteers = <your table of all Volunteers>
IQueryable<Appointment> appointments = <your table of all appointments>
// ceremonies are appointments with non-null Fee and non-zero Slots:
var ceremonies = appointments
.Where(appointment => appointment.Fee != null && appointment.Slots != 0);
var volunteersWithUserName = volunteers
.Where (volunteer => volunteer.UserName == userName);
// if Volunteer.UserName unique, this will lead to a sequence with one element
// if not unique, consider selection by Id
现在,为了获得这位志愿者没有参加的所有仪式,我首先需要参加志愿者参加的仪式。为此,我需要连接表。加入志愿者与仪式的联络表。
通常我会使用LINQ方法 - 语法而不是LINQ查询语法,因为它具有更多功能。 H owever a join with three tables looks horrible in method syntax.为此,我使用查询语法:
var attendedCeremonies = from volunteer in volunteersWithUserName
join volap in VolunteersAppointments on volap.VolunteerId equals volunteer.Id
join ceremony in ceremonies on volap.CeremonyId equals ceremony.Id
select ceremony;
var notAttendedCeremonies = ceremonties.Except(attendedCeremonies);
在您的申请中,我假设您不需要仪式的所有属性。您可能只想显示名称/描述/时间/位置。您还需要Id才能进行新的约会。
var displayableCeremonies = notAttendedCeremonies.Select(ceremony => new
{
Id = ceremony.Id,
Name = ceremony.Name,
Description = ceremony.Description,
Location = ceremony.Location,
Time = ceremony.Time,
Duration = ceremony.Duration,
});
请注意,尽管我创建了许多单独的LINQ查询,但尚未执行任何查询,因此尚未访问您的表。这些语句只更改了查询中的表达式。像这样写它而不是一个大的LINQ语句没有大的性能损失。奖金是它可读,因此更易于测试和维护。
以下将最终进行查询:
var desiredResult = displayableCeremonies.ToList();
使用实体框架时,您不需要自己执行连接。如果您使用ICollections,实体框架将理解需要三表连接。
class Volunteer
{
public int Id {get; set;}
// every volunteer has zero or more Appointments (many-to-many)
public virtual ICollection<Appointment> Appointments {get; set;}
...
}
class Appointment
{
public int Id {get; set}
// every Appointment is attended by zero or more Volunteers (many-to-many)
public virtual ICollection<Volunteer> Volunteers {get; set;}
...
}
public MyDbContext : DbContext
{
public DbSet<Volunteer> Volunteers {get; set;}
public DbSet<Appointment> Appointments {get; set;}
}
因为我坚持Entity Framework Code First Naming Conventions,这足以让实体框架理解我的意思是设计一个多对多的关系。实体框架将为我创建和维护联结表。我不需要这个表来执行我的查询。
using (var dbContext = new MyDbContext())
{
var ceremoniesNotAttendedByUser = dbContext.Appointments
// keep only the Ceremony appointments
// that are not attended by any Volunteer with UserName
.Where(appointment =>
// only ceremonies:
appointment.Fee != null && appointment.Slots != 0
// and not attended by any volunteer that has userName
// = sequence of UserNames of the volunteers that attend this appointment
// does not contain userName
&& !appointment.Volunteers.Select(volunteer => volunteer.UserName)
.Contains(userName))
// Fetch only the properties you want to display:
.Select(ceremony=> new
{
Id = ceremony.Id,
Name = ceremony.Name,
Description = ceremony.Description,
Location = ceremony.Location,
Time = ceremony.Time,
Duration = ceremony.Duration,
})
.ToList();
}
您看到我不需要联结表。实体框架对我来说更自然(我有一个任务由零个或多个志愿者参加)我敢于在一个声明中向您展示。