[英]Automapper : Ignore Navigation Properties
I've read the 2 proposed answers here and these 2 answers do not match what I want to do as they are manual work.我在这里阅读了 2 个建议的答案,这 2 个答案与我想做的不匹配,因为它们是手动工作。 So If I add another navigation property, I would need to modify AutoMapper config.因此,如果我添加另一个导航属性,我将需要修改 AutoMapper 配置。
The main goal is to make EF objects serializable, without removing lazy loading.主要目标是在不删除延迟加载的情况下使 EF 对象可序列化。
I'm looking to write something like that:我想写这样的东西:
cfg.CreateMap<EntityA, EntityA>(new IgnoreNavigationsProperties());
I'm not looking to identify each property one by one.我不想一一识别每个属性。 It should use reflecion.它应该使用反射。 (I can manage reflection part, just need some help to get started to how I could do that code.). (我可以管理反射部分,只需要一些帮助来开始我如何编写该代码。)。
Any help or direction is welcome !欢迎任何帮助或指导!
Edit:编辑:
So I start to get somewhere with converters.所以我开始使用转换器。
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
public class EfEntityConverter<T> : ITypeConverter<T, T> where T : BaseEntity
{
/// <summary>
///
/// </summary>
/// <param name="source"></param>
/// <param name="destination"></param>
/// <param name="context"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public T Convert(T source, T destination, ResolutionContext context)
{
}
}
But I get a lot of warnings (Which I treat as errors. And If I implement that converter, that will be horrible performances as Convert will be executed each time and I would run reflexion on each object.但是我收到了很多警告(我将其视为错误。如果我实现该转换器,那将是可怕的表现,因为每次都会执行 Convert,并且我会在每个 object 上运行反射。
So, any idea how to make it better?那么,知道如何让它变得更好吗? (Sometiomes, I need to run it on 100.000+ objects) (有时,我需要在 100.000 多个对象上运行它)
Reflection can't tell you everything about EF Core's data model. Instead you can build a hashset of all your navigation properties from your DbContext.Model
;反射无法告诉您有关 EF Core 数据 model 的所有信息。相反,您可以从DbContext.Model
构建所有导航属性的哈希集;
using var scope = provider.CreateScope();
var db = scope.GetRequiredService<MyContext>();
var model = db.Model;
var entities = model.GetEntityTypes();
var navigationProperties = entities
.SelectMany(e => e.GetNavigations())
// ignore owned type navigations, treat them as part of the data;
.Where(n => !n.ForeignKey.IsOwnership && n.PropertyInfo!=null)
.Select(n => n.PropertyInfo)
.Concat(
entities
.SelectMany(e => e.GetSkipNavigations())
.Where(n => n.PropertyInfo!=null)
.Select(n => n.PropertyInfo)
)
.ToHashSet();
You'll want to store this hashset somewhere as a singleton, so you only build it once, or perhaps once per entity type.您需要将此哈希集作为 singleton 存储在某处,因此您只需构建一次,或者每个实体类型一次。
From there you probably want to dynamically build an expression tree equivalent to t => new T{ A = tA, .... };
从那里你可能想动态构建一个表达式树,相当于t => new T{ A = tA, .... };
, skipping any navigation properties from your model. , 跳过 model 中的任何导航属性。
var parm = Expression.Parameter(typeof(T), "t");
var expr = Expression.Lambda<Func<T,T>>(
Expression.MemberInit(
Expression.New(typeof(T)),
typeof(T)
.GetProperties()
.Where(p => p.CanRead && p.CanWrite)
.Except(navigationProperties)
.Select(p => Expression.Bind(p, Expression.MakeMemberAccess(parm, p)))
),
parm
);
var factoryMethod = expr.Compile();
Now you can call this method from your .Convert()
method to create the copy of the object.现在您可以从.Convert()
方法调用此方法来创建 object 的副本。
Though this trivial implementation will only make a shallow copy of each property.尽管这个微不足道的实现只会对每个属性进行浅表复制。 For some property types, such as owned types, a deep copy would be needed.对于某些属性类型,例如自有类型,需要深拷贝。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.