这是我正在使用的一组简化的表,它们被描述为类。我正在使用T4模板来创建简单的POCO。 我删除了可能使问题混乱的所有类的所有非必要属性。
public class MarketingPlan
{
public guid MarketingPlanID { get; set; }
public bool Disabled { get; set; }
public virtual ICollection<MarketingPlanItem> MarketingPlanItems { get; set; }
}
public partial class MarketingPlanItem
{
public System.Guid MarketingPlanItemID { get; set; }
public System.Guid MarketingPlanID { get; set; }
public System.Guid MarketingPlanItemTypeID { get; set; }
public bool Disabled { get; set; }
public Nullable<System.Guid> EmailTemplateID { get; set; }
public virtual EmailTemplate EmailTemplate { get; set; }
public virtual MarketingPlanItemType MarketingPlanItemType { get; set; }
}
public partial class EmailTemplate
{
public System.Guid EmailTemplateID { get; set; }
}
public partial class MarketingPlanItemType
{
public System.Guid MarketingPlanItemTypeID { get; set; }
}
我尝试创建的强类型结果不需要连接到Entity Framework上下文。这是我尝试解决方案。
public MarketingPlan GetMarketingPlanWithItems(Guid marketingPlanID)
{
var query =
this.Context
.MarketingPlanItems
.GroupJoin(this.Context.MarketingPlanItemTypes,
mpi => mpi.MarketingPlanItemTypeID,
mpit => mpit.MarketingPlanItemTypeID,
(mpi, mpit) =>
{
mpi.MarketingPlanItemType = mpit.FirstOrDefault();
return mpi;
})
.GroupJoin(this.Context.EmailTemplates,
mpi => mpi.EmailTemplateID,
et => et.EmailTemplateID,
(mpi, et) =>
{
mpi.EmailTemplate = et.FirstOrDefault();
return mpi;
})
.Where(mpi => mpi.Disabled == false);
var result =
this.Context
.MarketingPlans
.GroupJoin(query,
mp => mp.MarketingPlanID,
mpi => mpi.MarketingPlanID,
(mp, mpi) =>
{
mp.MarketingPlanItems = mpi.ToList();
return mp;
})
.Where(mp => mp.MarketingPlanID == marketingPlanID)
.FirstOrDefault();
return result;
}
现在我意识到我无法在GroupJoin
中使用真正的匿名函数,因为它会抛出以下错误:
带有语句主体的lambda表达式无法转换为表达式树
我在这个例子中用这种方式编码,因为如果我new
是一个强类型的对象,我相信我必须填充每个我不想做的字段。
最终结果是;一个MarketingPlan
,其MarketingPlanItems
只填充了Disable
,EmailTemplate
填充了EmailTemplate或Null,每个MarketingPlanItem填充了MarketingPlanItemType
}}。这个sql可能看起来像(粗略地):
SELECT
mp.*,
mpi.*,
mpit.*,
et.*
FROM
MarketingPlan mp
LEFT JOIN MarketingPlanItem mpi
on mp.MarketingPlanID = mpi.MarketingPlanID
INNER JOIN MarketingPlanItemType mpit
on mpi.MarketingPlanItemTypeID = mpit.MarketingPlanItemTypeID
LEFT JOIN EmailTemplate et
on mpi.EmailTemplateID = et.EmailTemplateID
有没有办法在使用Lambda的Entity Framework中完成此操作而不对数据库发出多个请求?
更新1
public MarketingPlan GetMarketingPlanWithItems(Guid marketingPlanID)
{
MarketingPlan result = null;
var query = this.Context.MarketingPlanItems
.Include("MarketingPlan")
.Include("MarketingPlanItemType")
.Include("EmailTemplate")
.Include("EmailTemplate.EmailTemplateCategory")
.Where(mp => !mp.Disabled
&& !mp.MarketingPlan.Disabled
&& mp.MarketingPlanID == marketingPlanID)
.ToList();
var query2 = query.FirstOrDefault();
if (query2 != null)
{
result = query2.MarketingPlan;
result.MarketingPlanItems = query;
}
return result;
}
这最终归还了我需要的东西。
答案 0 :(得分:3)
你不能只返回计划项吗?
如:
var items = this.Context.MarketingPlanItems
.Where(x => !x.Disabled && !x.MarketingPlan.Disabled)
返回的每件商品都有一个关联的电子邮件模板。只需将其作为item.EmailTemplate
使用,不需要手动连接。
对于该结果,您可以item.MarketingPlan.MarketingPlanID
之类的最终分组,例如您自己的Dictionary<MarketingPlan, IList<MarketingPlanItem>>
或自定义Type
,代表每个计划及其已启用的项目,而无需实际需要创建任何新实体。
为什么不利用ORM为您解决关系? 注意SELECT N + 1问题,并确保EF获取所有关联实体。 比如使用:
this.Context.MarketingPlanItems
.Include(i => i.MarketingPlan)
.Include(i => i.EmailTemplate)
您还可以在MarketingPlan
类型上编写扩展方法,以返回一个表达式,该表达式返回其上的已启用项目,并将其与Linq一起使用。
答案 1 :(得分:1)
如果我没弄错,你想为MarketingPlans加载相关的子项。
为什么不使用Include()?使用这样的东西:
this.Context.MarketingPlans.Include("MarketingPlanItems.EmailTemplates")