我有以下实体模型。为简洁起见,我在每个实体上省略了很多属性。
public sealed class Platform {
/// <summary>
/// Get and Set Platform's Unique Identifier.
/// </summary>
public int Id { get; set; }
/// <summary>
/// Determine if an Object is Equal to This Platform.
/// </summary>
/// <param name="obj">
/// An object to compare.
/// </param>
/// <returns>
/// A boolean true if the object is equal to this platform. A boolean false otherwise.
/// </returns>
public override bool Equals(object obj) {
bool isObjectPlatform = obj is Platform;
bool isObjectIdEqual = isObjectPlatform && (obj as Platform).Id == this.Id;
return isObjectIdEqual;
}
/// <summary>
/// Get Platform's Hash Code.
/// </summary>
/// <returns>
/// The platform's hash code, equalling the platform's unique identifier.
/// </returns>
public override int GetHashCode() {
return this.Id;
}
}
public sealed class Capture {
/// <summary>
/// Get and Set Capture's Unique Identifier.
/// </summary>
public int Id { get; set; }
/// <summary>
/// Get and Set Capture's Platform.
/// </summary>
public Platform Platform { get; set; }
/// <summary>
/// Determine if an Object is Equal to This Capture.
/// </summary>
/// <param name="obj">
/// An object to compare.
/// </param>
/// <returns>
/// A boolean true if the object is equal to this capture. A boolean false otherwise.
/// </returns>
public override bool Equals(object obj) {
bool isObjectCapture = obj is Capture;
bool isObjectIdEqual = isObjectCapture && (obj as Capture).Id == this.Id;
return isObjectIdEqual;
}
/// <summary>
/// Get Capture's Hash Code.
/// </summary>
/// <returns>
/// The capture's hash code, equalling the capture's unique identifier.
/// </returns>
public override int GetHashCode() {
return this.Id;
}
}
我基本上想要的是一个LINQ查询,当然由EF支持,这将使我获得由整个平台实体分组的捕获的数量。我希望能够返回对每个平台的引用,而不是其中一个属性,以及与之关联的每个 Capture 的计数。
我做了这个查询,效果很好:
var query = this._defaultContext.Captures
.Include(m => m.Platform)
.GroupBy(m => m.Platform.Id)
.Select(m => new {
PlatformId = m.Key,
Count = m.Count()
});
但正如您所看到的,我正在按平台的 Id 属性进行分组。我宁愿拥有的是:
var query = this._defaultContext.Captures
.Include(m => m.Platform)
.GroupBy(m => m.Platform)
.Select(m => new {
Platform = m.Key,
Count = m.Count()
});
这不起作用。它只是为数据库中的每条记录计数1。它看起来并不知道整个实体分组。我希望通过 GetHashCode 和 Equals 方法实现区分每个平台,但没有运气。
任何人都遇到过这样的情景?有什么办法吗?或者我必须手动执行此操作。我很讨厌,因为它可能会导致某种N + 1查询。
提前致谢。
答案 0 :(得分:1)
var query = this._defaultContext.Captures
.GroupBy(m => m.Platform.Id)
.Select(m => new {
Platform = m.FirstOrDefault().Platform,
Count = m.Count()
});
答案 1 :(得分:1)
我不确定你为什么采取这种方法。考虑在Platform和Capture之间实现双向导航(参见Configuring Relationships with the Fluent API),然后你可以将Captures和Counting变得简单。
public sealed class Platform
{
public ICollection<Capture> Captures { get; set; }
// the rest of the stuff
}
...
var query = this._defaultContext.Platforms.Include("Captures").Select(p => new { Platform = p, CaptureCount = p.Captures.Count() });
在转换为SQL时,这应该表达为:
SELECT Platform.Id, Platform.Name, COUNT(Captures.*)
FROM Platform LEFT OUTER JOIN Capture ON Capture.Platform_Id = Platform.Id
GROUP BY Platform.Id, Platform.Name
答案 2 :(得分:0)
GroupBy
默认使用EqualityComparer<T>.Default
。反过来,EqualityComparer<T>.Default
会查看T
是否实现IEquatable<T>
并使用它,如果是的话。
所以答案是实现IEquatable<T>
:
public sealed class Platform : IEquatable<Platform> {
public override bool Equals(Platform obj) {
return this.Equals((object)obj);
}
// rest of your code here
}
无论其
我怀疑这可以翻译成SQL。您可能必须将导航属性从Platform
定义为Captures
列表,这将在一个查询中为您提供对象。
要指定IEqualityComparer,只需在类中实现该接口:
public class PlatformComparer : IEqualityComparer<Platform>
{
public bool Equals(Platform p1, Platform p2)
{
if(p1 == null !! p2 == null) return false;
return p1.Id == p2.Id;
}
public int GetHashCode(Platform p)
{
if(p==null) throw new ArgumentNullExceltion("p");
return p.Id.GetHashCode();
}
}
并在GroupBy
:
.GroupBy(m => m.Platform, new PlatformComparer())