我有一个设置了延迟加载的数据库(需要)。 我还有一个ASP.NET MVC应用程序,它连接到数据库和' Does Stuff'。 数据库是在我的类中建模的。
我目前有3个使用继承的类:
public class DeliveryNotification
{
[Key]
public int Id { get; set; }
public Status Status { get; set; }
}
public class TrackedDelivery : DeliveryNotification
{
[Required]
public DateTime Date { get; set; }
[Required]
public DateTime Time { get; set; }
}
public class SignedForDelivery : TrackedDelivery
{
[Required]
public string Image { get; set; }
}
这些都使用名为' DeliveryNotification'
的单个表存储在数据库中我已获得DeliveryNotification ID,并希望获得所有信息。
我的一个控制器内部是这种方法:
var query = (from s in context.SignedForDeliverys
where s.Id == id
select s
).SingleOrDefault();
^尽管有一个带有ID
的DeliveryNotification,但这将返回nullvar deliveryNotifications = context.DeliveryNotifications.SingleOrDefault(o => o.Id == id);
^这将仅返回id和状态。
假设我已经获得了一个Id,我怎么能返回所有数据(最好是SignedForDeliverys)?
修改: 试图添加一个包括:
var signedForDeliverys = (from s in context.SignedForDeliverys.Include("TrackedDelivery ").Include("DeliveryNotification")
select s).ToList();
然后我收到此错误:
An exception of type 'System.InvalidOperationException' occurred in EntityFramework.SqlServer.dll but was not handled in user code
Additional information: A specified Include path is not valid. The EntityType 'ClassLibrary.SignedForDelivery' does not declare a navigation property with the name 'TrackedDelivery'.
答案 0 :(得分:3)
如果你想要SignedForDelivery
,你可以......
context.DeliveryNotifications.OfType<SignedForDelivery>().Single(n => n.Id == id)
// or .Find(id)
或者,如果每个子类型都有DbSet
个属性...
context.SignedForDeliveries.Single(n => n.Id == id) // or .Find(id)
...而且您已获得所有数据。
但是有更多的话要说。
根据您的描述,似乎在不知道预先输入类型的情况下通过Id获取对象是业务案例(或用例)。如果是这样,在我看来你不应该使用继承。你唯一能做的就是检索一个DeliveryNotification
,然后尝试将它转换为所有继承的类型以查看它是什么(因为鉴别器字段不是类模型的一部分)。那非常笨拙。
我不会通过继承来解决这个问题。我会使用一种类型,获取记录,然后决定哪些数据是相关的,例如通过将其映射到特定的视图模型或域类,具体取决于现在可以看到的Type
属性。这可以通过策略模式来完成,这是一种组合模式。 (参考&#34;构成而非继承&#34;辩论)。
此外,使用TPH继承(一个表),您无法强制执行特定属性(如Image
),因为它们应该在数据库表中可以为空。它是一个&#34;软&#34;从某种意义上说,它的执行取决于软件。其他继承方案TPT,TPC确实允许强有力的执行,但它们还有其他缺点。
简而言之,继承本身并不总是最好的模式,再加上ORM,它往往更好地避免。
答案 1 :(得分:1)
查询1:
var query = (from s in context.SignedForDeliverys
where s.Id == id
select s
).SingleOrDefault();
如果ID与SignedForDelivery
匹配,则应返回SignedForDelivery
。如果ID与DeliveryNotification
不匹配SignedForDelivery
,则它将返回null。
查询2:
var deliveryNotifications = context.DeliveryNotifications
.SingleOrDefault(o => o.Id == id);
如果ID与DeliveryNotification
匹配,则应返回DeliveryNotification
。要将其设为TrackedDelivery
或SignedForDelivery
,您需要将其投射:
var trackedDelivery = deliveryNotifications as DeliveryNotification;
if(trackedDelivery != null)
{
DateTime d = trackedDelivery.Date;
}
var signedForDelivery = deliveryNotifications as SignedForDelivery
if(signedForDelivery != null)
{
String image = signedForDelivery.Image;
}
查询3:
var signedForDeliverys = (from s in context.SignedForDeliverys
.Include("TrackedDelivery")
.Include("DeliveryNotification")
select s).ToList();
失败,因为Include方法的目的是load related entities。即通过导航属性相关的实体。 SignedForDelivery
未声明名称为TrackedDelivery