C# 使用ValueInjector将EntityFramework POCO复制到DTO,而不触发延迟加载列表和属性
使用ValueInjector将EntityFramework POCO的深层克隆创建到类似的DTO类中,我遇到了一个问题 如果我从一个具有多个相关实体/具有导航属性的子实体的复杂POCO对象注入到一个稍微简单的DTO中,ValueInjector似乎仍在接触多个属性值,并导致从数据库延迟加载此数据 我相信ValueInjector在准备将值注入指定目标时,会获取特定源对象中每个属性的值 我的实际项目相当复杂,但作为一个例子,我以NerdDinner为例,以更简单的方式复制了这个问题。 (NerdDinner是使用EF4()进行代码优先开发的一个示例 我有两个模型课C# 使用ValueInjector将EntityFramework POCO复制到DTO,而不触发延迟加载列表和属性,c#,entity-framework,entity-framework-4,valueinjecter,C#,Entity Framework,Entity Framework 4,Valueinjecter,使用ValueInjector将EntityFramework POCO的深层克隆创建到类似的DTO类中,我遇到了一个问题 如果我从一个具有多个相关实体/具有导航属性的子实体的复杂POCO对象注入到一个稍微简单的DTO中,ValueInjector似乎仍在接触多个属性值,并导致从数据库延迟加载此数据 我相信ValueInjector在准备将值注入指定目标时,会获取特定源对象中每个属性的值 我的实际项目相当复杂,但作为一个例子,我以NerdDinner为例,以更简单的方式复制了这个问题。 (Ner
public class Dinner
{
public int DinnerId { get; set; }
public string Title { get; set; }
public DateTime EventDate { get; set; }
public string Address { get; set; }
public string HostedBy { get; set; }
public virtual ICollection<RSVP> Rsvps { get; set; }
}
我还创建了一个DTO类:
public class DinnerDTO
{
public int DinnerId { get; set; }
public string Title { get; set; }
public DateTime EventDate { get; set; }
public string Address { get; set; }
public string HostedBy { get; set; }
}
注意我没有在我的dinterdto
中的Dinner
中找到Rsvps集合
同样重要的是,我正在使用克隆注射约定对对象进行深度克隆。这段代码在这里和许多其他站点都被建议作为执行深度克隆注射的方法。
此代码可在此处找到:
现在,为了强调发生的延迟加载,我插入了10000个RSVP,用于Id=1的晚餐
然后执行以下代码:
var dinner = nerdDinners.Dinners.Where(x => x.DinnerId == 1).FirstOrDefault();
DinnerDTO dinnerDTO = new DinnerDTO();
dinnerDTO.InjectFrom<CloneInjection>(dinner);
此更改强制RSVP列表的“急切加载”,并且正如预期的那样,延迟与查询在同一行,并且InjectFrom
行在没有任何延迟的情况下快速通过
我已经阅读了一些关于StackOverflow的相关文章,其中一些建议在datacontext上禁用然后启用LazyLoading。我试过了,虽然它确实有效,但感觉相当脏
我通读了这篇文章()和相关的代码,他的方法似乎是使用一些NHibernate方法来确定一个属性是否是未初始化的代理,并以某种方式将它们去掉。我在EF4中找不到类似的东西
这让我很困惑,因为Rsvps集合甚至不在我的DTO对象中,我甚至对它的价值都不感兴趣。
我认为ValueInjector代码不应该询问目标对象可能根本不关心的属性值
有什么方法可以在ValueInjector中重写此行为吗?以某种方式推迟对属性值的求值,直到它完全确定我需要该值,例如在ConventionInjection
的SetValue
方法中?这样至少不会对DTO甚至不需要的属性求值
我能想到的最好的解决方案是ValueInjector,或者一个自定义约定,以某种方式能够检测到一个已卸载的延迟加载属性,而不是对其求值,而是在目标上将该属性设置为null。但我认为这是不可能的
有没有更好的方法可以通过EF使用?我不想急于加载数据库中的所有内容
我是否完全离开了,问题根本不在ValueInjector中
*编辑*
我已经找到了一个解决方案并回答了这个问题,我仍然很好奇我是否做错了,或者是否有更好的方法。我觉得我找到了一个满意的答案来回答我自己的问题,所以我将自己结束这个问题。 我最后做了两件事 首先,我完全在dbContext上禁用了延迟加载。 dbContext构造函数中类似于此的内容
this.Configuration.LazyLoadingEnabled=false;
我并没有真正使用EF的延迟加载功能,所以关闭它并没有什么大损失。这只是意味着如果我想填充相关实体,我必须在查询的Include
中指定它们。没什么大不了的
我做的另一件事是修改深层克隆注入约定,使用这里找到的SmartConventionInjection
代码。除了注入速度比基本注入更快之外,它在调用SetValue
之前也不会触及属性值,因此即使我确实有一些延迟加载属性,它们也不会被延迟除非DTO也有那个财产,否则我会马上吻你!(友好而不具威胁性的方式)
var dinner = nerdDinners.Dinners.Where(x => x.DinnerId == 1).FirstOrDefault();
DinnerDTO dinnerDTO = new DinnerDTO();
dinnerDTO.InjectFrom<CloneInjection>(dinner);
var dinner = nerdDinners.Dinners.Where(x => x.DinnerId == 1).Include("RSVPs").FirstOrDefault();
DinnerDTO dinnerDTO = new DinnerDTO();
dinnerDTO.InjectFrom<CloneInjection>(dinner);