C# 实体框架-从另一个表获取数据的自定义字段
我有这样一个场景:C# 实体框架-从另一个表获取数据的自定义字段,c#,entity-framework,C#,Entity Framework,我有这样一个场景: 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 I
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; }
}
是的,您可以,但是使用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;}
}
公共类源代码
{
公共int ID{get;set;}
公共字符串名称{get;set;}
公共字符串说明{get;set;}
[未映射]
公共发票模板CurrentTemplate
{
得到
{
退票会员资格
.其中(i=i.EndDate==null)
.Select(i=>i.InvoiceTemplate)
.FirstOrDefault();
}
}
公共虚拟ICollection InvoiceMemberships{get;set;}
}
在我看来,要实现这一目标,需要满足的条件太多了:
不能直接用于LINQ查询:EF会抱怨表达式无法转换为SQLCurrentTemplate
- 您必须始终
Include()
才能在释放上下文后访问内存中的InvoiceMemberships.InvoiceTemplate
。这将始终为每个CurrentTemplate
对象(在一个查询中)加载所有源
+InvoiceMemberships
InvoiceTemplate
- 如果不使用
,您只能在释放上下文之前访问Include()
。这将在单独的查询中为每个CurrentTemplate
对象触发所有源
+invoicemembership
的延迟加载InvoiceTemplate
源代码
只需加载一个InvoiceMembership
所需的数据(远远)就可以了
最有效的方法是将所需数据查询到投影中,因此可以在SQL查询中包含谓词EndDate==null
我们必须等待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; }
}
在源代码中
:
[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();
}
}
所以,现在,你有了一个方法,而不是一个属性,不再隐藏这样一个事实,即每次你访问它时都会执行一个操作。。。ReadCurrentTemplate的名称告诉您这一点。为什么不现在就让它成为静态的呢?此外,将其设置为静态
意味着您不再需要担心NotMappedAttribute
但是我们仍然希望能够访问源代码
,不是吗(特别是如果删除ICollection
导航属性,正如我在您的评论中看到的,您希望这样做)?现在,这不再是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; }
}
readonly Lazy\u currentTemplate;
公共来源()
{
_currentTemplate=new Lazy(t=>t=InvoiceMembership.ReadCurrentTemplate(ID));
}
[未映射]
公共发票模板CurrentTemplate
{
获取{return\u currentTemplate.Value;}
}
因此,这样做,您仍然需要运行数据库查询来获取CurrentTemplate
的值,但只需要一次来评估懒惰的
私人支持者;之后,在该源对象的生命周期内,该属性将与第一次读取时相同。这似乎符合您将如何使用它的模型,考虑到在您的示例中它只是一个只读属性。它只适用于源对象的生命周期,该对象无论如何都应该在上下文中
如果不是,这也应该是源
上的方法ReadCurrentTemplate
(非静态
,无参数),只需直接返回InvoiceMembership.ReadCurrentTemplate(ID)
,指示每次调用时它都在从数据库中读取。它需要在数据库中,还是只需要一个基于invoicememberships中的内容计算的字段?在这种情况下,只需创建一个成员并用[NotMapped]装饰它,我就可以编辑我的帖子@PhilipStuyck…我在数据库中不需要它谢谢@Gert Arnold。。。我还有一个问题,如果我想删除源
实体中InvoiceMembership
的导航,那么如何获取CurrentTemplate
?@Mahdi如果出现新问题,最好问一个新问题。在StackOverflow,我们不像大多数论坛那样创建线程。我们如何在DTO中引用这个NotMapped字段<代码>公共发票模板CurrentTemplate{get;}
是这样吗?
readonly Lazy<InvoiceTemplate> _currentTemplate;
public Source()
{
_currentTemplate = new Lazy<InvoiceTemplate>(t => t = InvoiceMembership.ReadCurrentTemplate(ID));
}
[NotMapped]
public InvoiceTemplate CurrentTemplate
{
get { return _currentTemplate.Value; }
}