这个问题是基于我上周问过的问题:Recursive linq to get infinite children。那篇文章给出的答案产生了我所需要的东西;基于父级的不同位置及其子级列表。我们需要使用我们自己的Locations模型,所以我们创建了一个,从那时起,我一直在获得重复的结果。我们的模型非常基础:
class LocationModel
{
public int LocationID { get; set; }
public int ParentLocationID { get; set; }
public string LocationName { get; set;}
}
如果将它与EF创建的实体进行比较,我只会删除所有不需要/使用的字段(参见上面的链接)。所以我修改了我的linq语句来改为使用这个新模型:
DBEntities db = new DBEntities();
public IEnumerable<LocationModel> GetAllChildLocations(int parentId)
{
var locations = (from l in db.Locations
where l.ParentLocationID == parentId ||
l.LocationID == parentId
select new LocationModel()
{
LocationID = l.LocationID,
ParentLocationID = l.ParentLocationID,
LocationName = l.LocationName
}).ToList();
var children = locations.AsEnumerable()
.Union(db.Locations.AsEnumerable()
.Where(x => x.ParentLocationID == parentId)
.SelectMany(y => GetAllChildLocations(y.LocationID)))
.ToList();
return children.OrderBy(l => l.LocationName);
}
当我在Visual Studio或LinqPad中运行它时,我现在得到了重复项。这是不产生重复项的原始代码:
public IEnumerable<Location> GetAllChildLocations(int parentId)
{
var locations = (from l in db.Locations
where l.ParentLocationID == parentId ||
l.LocationID == parentId
select l).ToList();
var child = locations.AsEnumerable()
.Union(db.Locations.AsEnumerable()
.Where(x => x.ParentLocationID == parentId)
.SelectMany(y => GetAllChildLocations(y.LocationID)))
.ToList();
return child;
}
为什么当我使用自己的模型而不是EF生成的模型时,它会产生重复?是否与EF模型具有的自动生成字段有关,而我的不是?
答案 0 :(得分:3)
为什么当我使用自己的模型而不是EF中生成的模型时会产生重复?
因为您使用的是Enumerable.Union
方法,默认情况下使用引用相等。 EF DbContext
更改跟踪器使用相同的PK在内部(跟踪)已加载的实体对象实例(即使您通过单独的数据库查询检索它们),因此引用相等也可以。对于查询new LocationModel
运算符创建的select
实例,无法说明。
解决此问题的一种方法是在GetHashCode
课程中实施Equals
和LocationModel
。但总的来说,我不喜欢递归子检索的实现和Union
的使用 - 必须有更好的方法,但这超出了这个问题的范围(但对于链接)。
邪恶的根源是以下条件
where l.ParentLocationID == parentId || l.LocationID == parentId
选择项目及其子项,导致结果集中的重复项,然后应该由Union
方法消除。好的实现根本不会产生重复。