为 TreeList DataSource 组合来自不同对象类型的多个 IQueryable
Combining multiple IQueryable from different object types for TreeList DataSource
我正在寻找一种方法来组合来自不同对象类型的两个或多个 IQueryable,以便将其用作我的树列表的数据源。
对于树列表,我使用 DevExpress WinForms 组件“TreeList”。
它为我提供了通常映射到“ID”的属性“KeyFieldName”和映射到父 ID 的 ParentFieldName 以构建层次结构。
我使用 entity framework 6 作为或映射器。
我有以下两个 类 我需要合并:
XObject:
[Table("tbl_objects")]
public class XObject
{
[Column("id")]
public int Id { get; set; }
[Column("display_name")]
public String DisplayName { get; set; }
[Column("description")]
public String Description { get; set; }
[Column("usage_reason")]
public String UsageReason { get; set; }
[Column("is_network_compatible")]
public bool IsNetworkCompatible { get; set; }
[Column("ip_address")]
public String IpAddress { get; set; }
[Column("network_name")]
public String NetworkName { get; set; }
[Column("serial_number")]
public String SerialNumber { get; set; }
[Column("manufacturer_identification_code")]
public String ManufacturerIdentificationCode { get; set; }
[Column("web_link")]
public String WebLink { get; set; }
[Column("warranty")]
public int WarrantyInDays { get; set; }
[Column("ref_manufacturer")]
public virtual XManufacturer Manufacturer { get; set; }
[Column("ref_order")]
public virtual XOrder Order { get; set; }
[Column("ref_owner")]
public virtual XOwner Owner { get; set; }
[Column("ref_room")]
public virtual XRoom Room { get; set; }
[Column("ref_object_folder")]
public virtual XObjectFolder ObjectFolder { get; set; }
public virtual ICollection<XAdditionalObjectData> AdditionalObjectData { get; set; }
}
XObjectFolder:
[Table("tbl_object_folders")]
public class XObjectFolder
{
[Column("id")]
public int Id { get; set; }
[Column("display_name")]
public String DisplayName { get; set; }
[Column("short_name")]
public String ShortName { get; set; }
[Column("ref_parent_folder")]
public virtual XObjectFolder ParentFolder { get; set; }
public virtual ICollection<XObjectFolder> ChildFolders { get; set; }
public virtual ICollection<XObject> Objects { get; set; }
[NotMapped]
public int ParentFolderId { get { return ParentFolder == null ? -1 : ParentFolder.Id; } }
}
您可能已经看到,对象文件夹可以包含子文件夹,也可以包含对象。
我的目标是将其视为我的树列表中的一个“数据源”。
例如像这样:
- 对象文件夹 A
-
- 对象子文件夹 A
-
-
- 对象 1
-
- 对象 1
在这里的其他问题中,我发现了连接或合并可查询对象的可能性,但这只适用于相同类型的对象:
using (var db = new XDbContext(_conString))
{
// Queryables
var ofs = from of in db.ObjectFolders orderby of.DisplayName ascending select of; // <- All ObjectFolders
var obs = from obj in db.Objects orderby obj.DisplayName ascending select obj; // <- All Objects
// Concat them
var comb = ofs.Concat(obs); // <- not the same type
// As DataSource for my TreeList
TreeListObjects.DataSource = comb.ToList();
}
这就是为什么我正在寻找一种使这成为可能的好方法。
我也可以想象我使用一种非常糟糕的方法来实现我的目标。所以我愿意接受建议。这是我为了提高自己的个人项目。
提前致谢!
编辑
所以我设法通过使用一个接口更进一步 类 共享:
public interface ITreeListCombinable
{
int Id { get; set; }
int ParentId { get; }
String DisplayName { get; set; }
}
但是...谁会想到...又出现了一个问题:
看看数据库结构:
Db_Struture
由于两个对象都存储在不同的表中,因此将它们合并时,id 肯定不是唯一的。
这在设置数据源时是必需的。
解法:
所以我对我的问题采取了自己的方法并且成功了。
完全公开 -> 我认为自己是初学者,所以这个解决方案可能不是最好的。尽管如此,如果有人处于类似情况,那么它是如何工作的:
首先我创建了一个界面,文件夹和对象共享:
ITreeListCombinable
public interface ITreeListCombinable
{
int Id { get; set; }
int ParentId { get; }
int ListId { get; set; }
int ParentListId { get; set; }
String DisplayName { get; set; }
ObjectTreeListElementTypes TreeListElementType { get; }
}
然后我确定,我的 XObject 和 XObjectFolder 类 都持有它们对应的 ObjectTreeListElementTypes 值:
ObjectTreeListElementTypes 枚举:
public enum ObjectTreeListElementTypes
{
Folder,
Object
}
类:
[NotMapped]
public ObjectTreeListElementTypes TreeListElementType => ObjectTreeListElementTypes.Folder; // or *.Object for that matter
所以后来我写了我自己的“控制器”来处理我的特定场景。
ObjectTreeListElementController:
public class ObjectTreeListElementController
{
private List<ITreeListCombinable> _list;
public ObjectTreeListElementController()
{
_list = new List<ITreeListCombinable>();
}
public void AddRange(List<ITreeListCombinable> list)
{
// add incoming items to private _list
_list.AddRange(list);
}
public List<ITreeListCombinable> GetDataSourceList()
{
// create auto increment list id
var listId = 0;
foreach (var item in _list)
{
item.ListId = listId;
listId++;
}
// set new parent list id according to incremental list id
foreach (var item in _list)
{
var parents = _list.Where(x => x.Id == item.ParentId && x.TreeListElementType == ObjectTreeListElementTypes.Folder);
if (parents.Count() > 0)
item.ParentListId = parents.First().ListId;
else
item.ParentListId = -1;
}
return _list;
}
}
本质上,在调用GetDataSourceList()方法时,它首先分发增量的、临时的list-id。
在第二个循环中,我然后搜索原始父 ID 并匹配树列表元素类型。如果找到 none,则此文件夹是我的树列表中的根文件夹,如果找到,给定的列表 ID 将成为父列表 ID:
using (var db = new XDbContext(_conString))
{
// Queryables
IQueryable<ITreeListCombinable> ofs = from of in db.ObjectFolders orderby of.DisplayName ascending select of;
IQueryable<ITreeListCombinable> objs = from obj in db.Objects orderby obj.DisplayName ascending select obj;
var lofs = ofs.ToList();
var lobjs = objs.ToList();
var ctrl = new ObjectTreeListElementController();
ctrl.AddRange(lofs);
ctrl.AddRange(lobjs);
var sourceList = ctrl.GetDataSourceList();
// As DataSource for my TreeList
TreeListObjects.DataSource = sourceList;
}
这给我带来了我想要的确切输出:
希望这对另一个初学者有帮助:)
我正在寻找一种方法来组合来自不同对象类型的两个或多个 IQueryable,以便将其用作我的树列表的数据源。
对于树列表,我使用 DevExpress WinForms 组件“TreeList”。 它为我提供了通常映射到“ID”的属性“KeyFieldName”和映射到父 ID 的 ParentFieldName 以构建层次结构。
我使用 entity framework 6 作为或映射器。
我有以下两个 类 我需要合并:
XObject:
[Table("tbl_objects")]
public class XObject
{
[Column("id")]
public int Id { get; set; }
[Column("display_name")]
public String DisplayName { get; set; }
[Column("description")]
public String Description { get; set; }
[Column("usage_reason")]
public String UsageReason { get; set; }
[Column("is_network_compatible")]
public bool IsNetworkCompatible { get; set; }
[Column("ip_address")]
public String IpAddress { get; set; }
[Column("network_name")]
public String NetworkName { get; set; }
[Column("serial_number")]
public String SerialNumber { get; set; }
[Column("manufacturer_identification_code")]
public String ManufacturerIdentificationCode { get; set; }
[Column("web_link")]
public String WebLink { get; set; }
[Column("warranty")]
public int WarrantyInDays { get; set; }
[Column("ref_manufacturer")]
public virtual XManufacturer Manufacturer { get; set; }
[Column("ref_order")]
public virtual XOrder Order { get; set; }
[Column("ref_owner")]
public virtual XOwner Owner { get; set; }
[Column("ref_room")]
public virtual XRoom Room { get; set; }
[Column("ref_object_folder")]
public virtual XObjectFolder ObjectFolder { get; set; }
public virtual ICollection<XAdditionalObjectData> AdditionalObjectData { get; set; }
}
XObjectFolder:
[Table("tbl_object_folders")]
public class XObjectFolder
{
[Column("id")]
public int Id { get; set; }
[Column("display_name")]
public String DisplayName { get; set; }
[Column("short_name")]
public String ShortName { get; set; }
[Column("ref_parent_folder")]
public virtual XObjectFolder ParentFolder { get; set; }
public virtual ICollection<XObjectFolder> ChildFolders { get; set; }
public virtual ICollection<XObject> Objects { get; set; }
[NotMapped]
public int ParentFolderId { get { return ParentFolder == null ? -1 : ParentFolder.Id; } }
}
您可能已经看到,对象文件夹可以包含子文件夹,也可以包含对象。 我的目标是将其视为我的树列表中的一个“数据源”。 例如像这样:
- 对象文件夹 A
-
- 对象子文件夹 A
-
-
- 对象 1
-
-
- 对象 1
在这里的其他问题中,我发现了连接或合并可查询对象的可能性,但这只适用于相同类型的对象:
using (var db = new XDbContext(_conString))
{
// Queryables
var ofs = from of in db.ObjectFolders orderby of.DisplayName ascending select of; // <- All ObjectFolders
var obs = from obj in db.Objects orderby obj.DisplayName ascending select obj; // <- All Objects
// Concat them
var comb = ofs.Concat(obs); // <- not the same type
// As DataSource for my TreeList
TreeListObjects.DataSource = comb.ToList();
}
这就是为什么我正在寻找一种使这成为可能的好方法。
我也可以想象我使用一种非常糟糕的方法来实现我的目标。所以我愿意接受建议。这是我为了提高自己的个人项目。
提前致谢!
编辑
所以我设法通过使用一个接口更进一步 类 共享:
public interface ITreeListCombinable
{
int Id { get; set; }
int ParentId { get; }
String DisplayName { get; set; }
}
但是...谁会想到...又出现了一个问题:
看看数据库结构: Db_Struture
由于两个对象都存储在不同的表中,因此将它们合并时,id 肯定不是唯一的。 这在设置数据源时是必需的。
解法:
所以我对我的问题采取了自己的方法并且成功了。
完全公开 -> 我认为自己是初学者,所以这个解决方案可能不是最好的。尽管如此,如果有人处于类似情况,那么它是如何工作的:
首先我创建了一个界面,文件夹和对象共享:
ITreeListCombinable
public interface ITreeListCombinable
{
int Id { get; set; }
int ParentId { get; }
int ListId { get; set; }
int ParentListId { get; set; }
String DisplayName { get; set; }
ObjectTreeListElementTypes TreeListElementType { get; }
}
然后我确定,我的 XObject 和 XObjectFolder 类 都持有它们对应的 ObjectTreeListElementTypes 值:
ObjectTreeListElementTypes 枚举:
public enum ObjectTreeListElementTypes
{
Folder,
Object
}
类:
[NotMapped]
public ObjectTreeListElementTypes TreeListElementType => ObjectTreeListElementTypes.Folder; // or *.Object for that matter
所以后来我写了我自己的“控制器”来处理我的特定场景。
ObjectTreeListElementController:
public class ObjectTreeListElementController
{
private List<ITreeListCombinable> _list;
public ObjectTreeListElementController()
{
_list = new List<ITreeListCombinable>();
}
public void AddRange(List<ITreeListCombinable> list)
{
// add incoming items to private _list
_list.AddRange(list);
}
public List<ITreeListCombinable> GetDataSourceList()
{
// create auto increment list id
var listId = 0;
foreach (var item in _list)
{
item.ListId = listId;
listId++;
}
// set new parent list id according to incremental list id
foreach (var item in _list)
{
var parents = _list.Where(x => x.Id == item.ParentId && x.TreeListElementType == ObjectTreeListElementTypes.Folder);
if (parents.Count() > 0)
item.ParentListId = parents.First().ListId;
else
item.ParentListId = -1;
}
return _list;
}
}
本质上,在调用GetDataSourceList()方法时,它首先分发增量的、临时的list-id。 在第二个循环中,我然后搜索原始父 ID 并匹配树列表元素类型。如果找到 none,则此文件夹是我的树列表中的根文件夹,如果找到,给定的列表 ID 将成为父列表 ID:
using (var db = new XDbContext(_conString))
{
// Queryables
IQueryable<ITreeListCombinable> ofs = from of in db.ObjectFolders orderby of.DisplayName ascending select of;
IQueryable<ITreeListCombinable> objs = from obj in db.Objects orderby obj.DisplayName ascending select obj;
var lofs = ofs.ToList();
var lobjs = objs.ToList();
var ctrl = new ObjectTreeListElementController();
ctrl.AddRange(lofs);
ctrl.AddRange(lobjs);
var sourceList = ctrl.GetDataSourceList();
// As DataSource for my TreeList
TreeListObjects.DataSource = sourceList;
}
这给我带来了我想要的确切输出:
希望这对另一个初学者有帮助:)