【发布时间】:2019-11-04 07:30:51
【问题描述】:
我们设计了一个资产管理系统来跟踪机构中流通的有形资产。我们使用ASP.NET MVC 架构和EF6 作为我们的ORM。
实体:
-
Asset是该机构拥有的设备,可以分配给其员工。 -
Person是对其给定资产负责的员工。 -
Location是机构内用于跟踪资产的单位。 -
MovementDoc是一份文档,其中包含有关资产大规模移动的详细信息(例如适合我们示例的重新分配/重新定位操作) -
AssetMovement是资产的任何单个移动过程详细信息。像Asset和MovementDoc之间的连接实体一样工作,但也有自己的属性,因此不是一次性的。
关系:
每个Asset 在其生命周期中都会遇到无数的运动过程。
public class Asset {
public ICollection<AssetMovement> Movements { get; set; }
}
AssetMovement 是需要记录的网桥实体
public class AssetMovement
{
public Asset Asset { get; set; }
public long? AssetId { get; set; }
public MovementDoc Document { get; set; }
public long? DocumentId { get; set; }
}
MovementDoc 可能包含许多AssetMovement,每个Asset 都与不同的Asset 相关。它可以同时指向Person 或Location。
public class MovementDoc
{
public Location TargetLocation { get; set; }
public long? TargetLocationId { get; set; }
public Person PersonReceived { get; set; }
public long? PersonReceivedId { get; set; }
public ICollection<AssetMovement> Movements { get; set; }
}
这个关系网络似乎适合我们的应用。但在实践中,它有一些缺点。
问题:
我们的用户希望在数据表中列出他们的资产以及分配的人员和位置信息。我们的第一种方法是在Asset 上创建一个计算属性:
[NotMapped, Computed]
public MovementDoc LastMovementDoc
{
get
{
if (Movements.Count == 0)
return null;
else
return Movements.Select(x => x.Document).OrderByDescending(x => x.DocumentDate).FirstOrDefault();
}
private set { }
}
这为我们提供了最后一次移动操作资产遭遇。所以我们可以从中提取人物和位置信息。它有效,我们将它用于列表和过滤(在DelegateDecompiler 库的帮助下转换为LINQ)。但它很慢,随着数据库的增长它会变慢。
最后,我们选择了一种更简单但更脏的方法:
public class Asset
{
public Person AssignedPerson { get; set; }
public long? AssignedPersonId { get; set; }
public Location AssignedLocation { get; set; }
public long? AssignedLocationId { get; set; }
}
是的,我们只是将Asset 绑定到它当前直接分配的Person 和Location(也保持旧关系)。发生新任务时会更新这些信息。
但感觉好像我们在这里遗漏了一些东西。创造额外的一级关系真的很聪明吗?或者有没有更有效的方法来处理这种关系复杂性?
顺便说一句,我们在全局范围内禁用了延迟加载,所以不要介意缺少 virtual 关键字。
【问题讨论】:
-
DocumentDate上是否有索引? -
我很难相信延迟加载已被禁用。原因是要么运动应该总是空的(除非你指定一个包含,但你没有包含最关键的代码,这是你如何检索资产,所以这都是猜测)或者你总是加载所有您检索的所有资产的移动(这非常低效)。您也没有缓存 select 的结果,所以每次一些代码访问属性时,查询都会再次运行,非常低效。
-
@GertArnold 不,没有。会有帮助吗?
-
是的,还有其他索引,比如
AssetMovement.DocumentId。
标签: c# asp.net-mvc database-design entity-framework-6