我一定是在失去理智......请看下面的内容
现在看看我正在查询的值:
你可以看到ETouchesEvent是null而Event不是......那么为什么Linq to SQL认为ETouchesEvent不为null?在我的第一张照片中,每个结果应为1。
[更新] 下面是生成的T-SQL,您可以清楚地看到它使用entityID来检查null
{SELECT
(CASE
WHEN ([t5].[EntityID]) IS NULL THEN @p1
WHEN ([t5].[EntityID]) IS NULL THEN @p2
ELSE @p3
END) AS [value]
FROM (
SELECT [t4].[ParticipationItemID], [t4].[EntityID]
FROM (
SELECT [t0].[ParticipationItemID], [t0].[IsLocalEvent], [t0].[IsProject], [t0].[IsOther], [t0].[EntityID], [t0].[IsEtouchesEvent]
FROM [ParticipationItem] AS [t0]
INNER JOIN [dbo].[Event] AS [t1] ON [t0].[EntityID] = ([t1].[Id])
WHERE [t0].[IsLocalEvent] = 1
UNION
SELECT [t2].[ParticipationItemID], [t2].[IsLocalEvent], [t2].[IsProject], [t2].[IsOther], [t2].[EntityID], [t2].[IsEtouchesEvent]
FROM [ParticipationItem] AS [t2]
INNER JOIN [ETouchesEvent] AS [t3] ON [t2].[EntityID] = ([t3].[ETouchesEventID])
WHERE [t2].[IsEtouchesEvent] = 1
) AS [t4]
) AS [t5]
WHERE ((([t5].[EntityID]) IS NOT NULL) OR (([t5].[EntityID]) IS NOT NULL)) AND (EXISTS(
SELECT NULL AS [EMPTY]
FROM [OrganisationParticipation] AS [t6]
WHERE (([t6].[OrganisationID]) = @p0) AND ([t6].[ParticipationitemID] = ([t5].[ParticipationItemID]))
))
}
这就是所有代码:
public List<int> GetParticipationYears(int? organisationID)
{
var result = (from p in GetParticipation(organisationID, null)
where p.ETouchesEvent != null || p.Event != null
select p.ETouchesEvent == null ? 1 : (p.Event == null ? 5 : 0));
//select p.IsEtouchesEvent ? p.ETouchesEvent.StartDate.Year : (p.IsLocalEvent ? p.Event.StartDate.Year : 0)); //<== this does work!
return result.Distinct().ToList();
}
public IQueryable<ParticipationItem> GetParticipation(int? organisationID, List<int> filterByYears)
{
var result = (from pi in DB.ParticipationItems
join e in DB.Events on pi.EntityID equals e.Id
where pi.IsLocalEvent
select pi)
.Union(
from pi in DB.ParticipationItems
join e in DB.ETouchesEvents on pi.EntityID equals e.ETouchesEventID
where pi.IsEtouchesEvent
select pi);
if (filterByYears != null)
result = result.Where(pi => (pi.IsEtouchesEvent && pi.ETouchesEvent != null && filterByYears.Contains(pi.ETouchesEvent.StartDate.Year)) ||
(pi.IsLocalEvent && pi.Event != null && filterByYears.Contains(pi.Event.StartDate.Year)));
if (organisationID.HasValue)
return result.Where(pi => pi.OrganisationParticipations.Any(x => x.OrganisationID == organisationID));
else
return result;
}
答案 0 :(得分:0)
确定。
所以问题可能来自你的联盟。
联盟的所有部分必须共享相同数量的字段(具有相同类型)。
在您的情况下,联盟起作用是因为Events
和ETouchesEvents
必须从同一个类继承,或实现相同的接口,或者只是相同。
但是这个联合生成的sql不能区分这两种类型(生成的CASE WHEN不能做你需要的,这是“连贯的”)。
因此,您必须检查sql可以区分的内容,这似乎只是IsLocalEvent
和IsEtouchesEvent
。
所以(如果我错了就改变逻辑)
var result = (from p in GetParticipation(organisationID, null)
// don't need a where clause, you're doing a join in your union, so any returned part will have an event (which might be a EtouchesEvent or an Event
select !p.IsEtouchesEvent
? 1
: !p.IsLocalEvent
? 5
: 0);
我同意这根本不直观,但有时你必须考虑“SQL”,而不仅仅是“Orm”。
如果你使用扁平化物体,而不是那种情况下的实体,那可能会更清楚。
点点滴滴。
在你的联合之后,pi.ETouchesEvent
上的任何测试都将生成与pi.Event
完全相同的sql(并且它们不能为空)。
所以我认为你也可以将年份测试更改为
if (filterByYears != null)
result = result.Where(pi => filterByYears.Contains(pi.ETouchesEvent.StartDate.Year);
答案 1 :(得分:0)
我没有找到关于此行为的任何文档,但似乎Linq to SQL转换正在查看关系背后的外键列(在本例中为EntityID),以查看它是否为空而不是链接记录。生成的SQL清楚地显示了这一点。