C# 具有linq to实体和自定义IEqualityComparer的distinct计数
我的自定义比较器似乎不工作。我想要一个不同对象的计数,但每次我都得到一个1的计数。尽管查看数据库本身可以清楚地看到,有1个以上的查询实例具有不同的“TimeOfAction”值C# 具有linq to实体和自定义IEqualityComparer的distinct计数,c#,linq,linq-to-entities,distinct,C#,Linq,Linq To Entities,Distinct,我的自定义比较器似乎不工作。我想要一个不同对象的计数,但每次我都得到一个1的计数。尽管查看数据库本身可以清楚地看到,有1个以上的查询实例具有不同的“TimeOfAction”值 class TimeComparer : IEqualityComparer<Action> { public bool Equals(Action a, Action b) { if (a.TimeOfAction == b.TimeOfAction)
class TimeComparer : IEqualityComparer<Action>
{
public bool Equals(Action a, Action b)
{
if (a.TimeOfAction == b.TimeOfAction)
return true;
else
return false;
}
public int GetHashCode(Action obj)
{
return obj.ToString().ToLower().GetHashCode();
}
}
类时间比较器:IEqualityComparer
{
公共布尔等于(行动a、行动b)
{
如果(a.TimeOfAction==b.TimeOfAction)
返回true;
其他的
返回false;
}
公共int GetHashCode(操作obj)
{
返回obj.ToString().ToLower().GetHashCode();
}
}
我想可能是GetHashCode方法,因为我不太熟悉它的工作原理。这是linq查询。由于Linq to Entities不支持distinct方法,因此我转换为AsEnumerable
DBEntities db = new DBEntities();
IEnumerable<Action> query =
from action in db.Action.AsEnumerable()
where action.TimeOfAction > new DateTime(2010, 11, 1, 0, 0, 0)
where action.TimeOfAction < new DateTime(2011, 2, 7, 0, 0, 0)
where action.EntityName == "seant"
select action;
var count = query.
Distinct(new TimeComparer()).Count();
DBEntities db=newdbentities();
IEnumerable查询=
来自db.action.AsEnumerable()中的操作
其中action.TimeOfAction>newdatetime(2010,11,1,0,0,0)
其中action.TimeOfAction
您的Equals和GetHashCode方法采用了完全不同的方法。特别是,假设Action,相等的对象可能有不同的散列码。ToString
使用的字段不是time of Action。他们必须保持一致,否则你绝对没有机会得到合理的结果。不相等的对象可以有相同的哈希代码(尽管这会影响性能),但是相等的对象必须给出相同的哈希代码
请注意,使用自定义比较器将强制在进程中而不是在数据库中完成不同的部分。这可能不是问题,你只需要理解它。编辑:我没有发现有一个超负荷的Queryable.Distinct
,它需要一个IEqualityComparer
。我的猜测是,这样您就可以提供自定义字符串比较器和一些其他著名的比较器。。。不仅仅是任意代码。如果可行,无论如何都要在本地完成。如果它爆炸了,我也不会感到惊讶
编辑:正如Marc所说,您可以使用Select(x=>x.TimeOfAction).Distinct().Count()
在数据库中执行此操作。不过,您还需要删除对AsEnumerable
的调用。我猜那是因为其他东西不起作用。你可以试试这个:
DBEntities db = new DBEntities();
IQueryable<DateTime> query =
from action in db.Action
where action.TimeOfAction > new DateTime(2010, 11, 1, 0, 0, 0)
where action.TimeOfAction < new DateTime(2011, 2, 7, 0, 0, 0)
where action.EntityName == "seant"
select action.TimeOfAction;
var count = query.Distinct().Count();
请注意,再次使用查询将生成第二个数据库查询。如果您需要计数与第二个查询所做的任何事情保持一致,那么您需要查看事务方面发生了什么。。。或者从数据库中提取所有详细信息(使用ToList
调用),然后在过程中执行不同的部分
返回自定义相等比较器 假设
TimeOfAction
是DateTime
或具有合理哈希代码的其他类型,则可以将类更改为:
class TimeComparer : IEqualityComparer<Action>
{
public bool Equals(Action a, Action b)
{
return a.TimeOfAction == b.TimeOfAction;
}
public int GetHashCode(Action obj)
{
return obj.TimeOfAction.GetHashCode();
}
}
您可以将其简化为:
return condition;
首先,请注意,这不会在db服务器上运行,因此这实际上与EF无关
我怀疑这部分是因为你的GetHashCode
不同意Equals
;理想情况下,您应该有以下内容:
public int GetHashCode(Action obj)
{
return obj.TimeOfAction.GetHashCode();
}
因为这就是你的所关心的
但是,请注意,整个查询可以通过以下方式重新编写(如果使用IQueryable查询
(并删除AsEnumerable()
),而不是IEnumerable查询
),可能会在db服务器上工作:
+最后一点是1,这是我将要添加到我的答案中的内容。我将把我的答案留给大家至少一段时间,因为我认为简化Equals方法的要点值得一看。不过,我很高兴你能把它包括在你的答案中,然后我会删除我的:)。。。注意对AsEnumerable的调用。他也需要删除:)@Jon-事实上,我认为OP指的是隐式演员阵容,但我已经添加了它anyway@Marc当前位置我在回答中也对这一点做了一定的详细说明。。。特别是在多个数据库查询等方面。因此,如果我将其作为IQueryable(通常的方式)保留,那么一切都发生在db服务器上,这就是为什么Distinct(IEqualityComparer)方法失败的原因,首先将其转换为IEnumerable?进行了建议的更改,并且成功了,谢谢。我只是想知道我是否仍然可以使用这些IEqualityComparer类,还是应该放弃它们?很好的细节(仍然使用IEnumerable
)。
return condition;
public int GetHashCode(Action obj)
{
return obj.TimeOfAction.GetHashCode();
}
var count = query.Select(x => x.TimeOfAction).Distinct().Count();