[英]How to create field and get data from joined table in Entity Framework 6
[英]Entity Framework - Custom Field that get data from another Table
我有这种情况:
public class Source
{
public int ID { get; set; }
public String Name { get; set; }
public String Description { get; set; }
public virtual ICollection<InvoiceMembership> InvoiceMemberships { get; set;}
}
public class InvoiceMembership
{
public int ID { get; set; }
[Column(TypeName = "date")]
public DateTime StartDate { get; set; }
[Column(TypeName = "date")]
public DateTime? EndDate { get; set; }
public virtual Source source { get; set; }
public virtual InvoiceTemplate InvoiceTemplate { get; set; }
}
public class InvoiceTemplate
{
public int ID { get; set; }
public String Name { get; set; }
public String Description { get; set; }
public bool Enabled { get; set; }
public int NumberOfPayment { get; set; }
}
如何在相关InvoiceMembership
行中具有EndDate=null
Source
实体中具有InvoiceTemplate
类型的名为CurrentTemplate
的字段?
编辑:
我使用波纹管代码,但这不是真正的方法!
[NotMapped]
public InvoiceTemplate CurrentTemplate { get {
var context=new MedicalContext();
var template = context.InvoiceMemberships.Where(m => m.source == this).Where(m => m.EndDate == null).Select(m => m.InvoiceTemplate);
if (template != null)
return (InvoiceTemplate)template;
else
return null;
} }
是的,您可以,但是使用EF计算属性非常麻烦。
假设您有:
public class Source
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
[NotMapped]
public InvoiceTemplate CurrentTemplate
{
get
{
return InvoiceMemberships
.Where(i = i.EndDate == null)
.Select(i => i.InvoiceTemplate)
.FirstOrDefault();
}
}
public virtual ICollection<InvoiceMembership> InvoiceMemberships { get; set;}
}
(我认为)要完成这项工作需要满足太多条件:
CurrentTemplate
:EF会抱怨该表达式无法转换为SQL。 Include()
InvoiceMemberships.InvoiceTemplate
才能访问内存中的CurrentTemplate
。 这将始终为每个Source
对象加载所有 InvoiceMemberships
+ InvoiceTemplate
(在一个查询中)。 Include()
,则只能在处置上下文之前访问CurrentTemplate
。 这将在单独的查询中触发每个Source
对象的所有 InvoiceMemberships
+ InvoiceTemplate
延迟加载。 如您所见, InvoiceMembership
每个Source
仅获得一个InvoiceMembership
相比,您将总是加载(远远多于)所需的数据。
最有效的方法是将所需数据查询到投影中,因此谓词EndDate == null
可以包含在SQL查询中。
我们将不得不等待NHibernate样式的公式属性。
直接在InvoiceMembership
POCO中公开您的外键值(如果存在关系,无论如何它都必须存在于数据库中),并且整个查询将通过L2E直接转换为SQL:
public class InvoiceMembership
{
public int ID { get; set; }
public int SourceId { get; set; }
[ForeignKey("SourceId")]
public virtual Source Source { get; set; }
public virtual InvoiceTemplate InvoiceTemplate { get; set; }
}
并在Source
:
[NotMapped]
public InvoiceTemplate CurrentTemplate
{
get
{
using (var context = new MedicalContext())
return context.InvoiceMemberships
.Where(m => m.SourceId == this.ID)
.Where(m => m.EndDate == null)
.Select(m => m.InvoiceTemplate)
.FirstOrDefault();
}
}
但是,这样做的缺点是-每次访问该属性时-都会查询数据库。 最好将此方法移至InvoiceMembership
类,在该类中您无论如何都将装入InvoiceMembership
对象,并使其成为一种方法:
public class InvoiceMembership
{
public int ID { get; set; }
public int SourceId { get; set; }
[ForeignKey("SourceId")]
public virtual Source Source { get; set; }
public virtual InvoiceTemplate InvoiceTemplate { get; set; }
static public InvoiceTemplate ReadCurrentTemplate(int sourceId)
{
using (var context = new MedicalContext())
return context.InvoiceMemberships
.Where(m => m.SourceId == sourceId)
.Where(m => m.EndDate == null)
.Select(m => m.InvoiceTemplate)
.FirstOrDefault();
}
}
CurrentTemplate tells you that. 因此,现在,您有了一个方法 (而不是属性),不再隐藏每次访问该操作时都会执行的事实……名称 CurrentTemplate告诉您。 为何现在不使其static
呢? 此外,将其设置为static
意味着您不再需要担心NotMappedAttribute
。
但是我们仍然想在Source
进行访问,不是ICollection<InvoiceMembership>
(特别是如果删除ICollection<InvoiceMembership>
导航属性,正如我希望在您的评论中看到的那样)? 现在,这不再是EF的关注点,而是Source
类中的常规延迟加载(如果您愿意)的关注点:
readonly Lazy<InvoiceTemplate> _currentTemplate;
public Source()
{
_currentTemplate = new Lazy<InvoiceTemplate>(t => t = InvoiceMembership.ReadCurrentTemplate(ID));
}
[NotMapped]
public InvoiceTemplate CurrentTemplate
{
get { return _currentTemplate.Value; }
}
因此,这样做,您仍然需要运行数据库查询来获取CurrentTemplate
的值,但是只有一次可以评估Lazy
私有支持者。 之后,在此Source
对象的生存期内,此属性将与第一次读取该属性相同。 考虑到示例中它只是一个只读属性,因此这似乎符合您将如何使用它的模型。 而且仅在Source
对象的生存期内,无论如何都应在上下文中。
如果不是,这应该是方法ReadCurrentTemplate
(非static
的,没有参数) Source
的欢迎,并简单地返回InvoiceMembership.ReadCurrentTemplate(ID)
直接,表示每次它被称为它是从数据库中读取。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.