从 EF Core 加载时计算 NotMapped 属性

2023-12-08

我们确实有一个实体类定义如下:

[Table("Users", Schema = "Mstr")]
[Audited]
public class User
{
    public virtual string FamilyName { get; set; }

    public virtual string SurName { get; set; }
    
    [NotMapped]
    public virtual string DisplayName
    {
        get => SurName + " " + FamilyName;
        private set { }
    }
}

这工作得很好。现在我们要提取逻辑部分SurName + " " + FamilyName到通常通过依赖注入注入的帮助器类。不幸的是 DI 不适用于实体类。

因此我的问题是:有什么方法可以拦截新 User 对象的创建吗?在 EF 创建 User 对象后,我是否可以重写 EF 中的方法来执行一些附加逻辑?


实际上(至少在 EF Core 6 中)您可以在构造实体时使用 DI。解决方案有点 hacky,并且基于 EF Core 功能inject“本机”服务(例如上下文本身)进入实体构造函数:

目前,只能注入 EF Core 已知的服务。正在考虑在未来版本中支持注入应用程序服务。

And AccessorExtensions.GetService<TService>扩展方法似乎支持从 DI 解析服务。

所以基本上只是介绍接受你的演员DbContext作为实体的参数并调用GetService并使用服务:

public class MyEntity
{
    public MyEntity()
    {        
    }

    public MyEntity(SomeContext context)
    {
        var valueProvider = context.GetService<IValueProvider>();
        NotMapped = valueProvider.GetValue();
    }

    public int Id { get; set; }

    [NotMapped]
    public string NotMapped { get; set; }
}


// Example value provider:
public interface IValueProvider
{
    string GetValue();
}

class ValueProvider : IValueProvider
{
    public string GetValue() => "From DI";
}

示例上下文:

public class SomeContext : DbContext
{
    public SomeContext(DbContextOptions<SomeContext> options) : base(options)
    {
    }

    public DbSet<MyEntity> Entities { get; set; }
}

例子:

var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<IValueProvider, ValueProvider>();
serviceCollection.AddDbContext<SomeContext>(builder => 
    builder.UseSqlite($"Filename={nameof(SomeContext)}.db"));
var serviceProvider = serviceCollection.BuildServiceProvider();
// init db and add one item
using (var scope = serviceProvider.CreateScope())
{
    var someContext = scope.ServiceProvider.GetRequiredService<SomeContext>();
    someContext.Database.EnsureDeleted();
    someContext.Database.EnsureCreated();
    someContext.Add(new MyEntity());
    someContext.SaveChanges();
}

// check that value provider is used
using (var scope = serviceProvider.CreateScope())
{
    var someContext = scope.ServiceProvider.GetRequiredService<SomeContext>();
    var myEntities = someContext.Entities.ToList();
    Console.WriteLine(myEntities.First().NotMapped); // prints "From DI"
}

注意var valueProvider = context.GetRequiredService<IValueProvider>();如果服务未注册,则会抛出异常,因此下一个实现可能会更好:

public MyEntity(SomeContext context)
{
    var serviceProvider = context.GetService<IServiceProvider>();
    var valueProvider = serviceProvider.GetService<IValueProvider>();
    NotMapped = valueProvider?.GetValue() ?? "No Provider";
}

您还可以考虑删除未映射的属性,并使用它和服务创建单独的模型来执行映射。

同样在 EF Core 的第 7 版中new hook对于这种情况应该添加。看到这个github issue.

UPD。 EF Core 7 方法。

EF 7 添加了IMaterializationInterceptor(以及其他一些 - 请参阅docs) 正好可以用于此目标。因此更新后的代码可能如下所示:

不需要 ctor 接受实体中的上下文:

public class MyEntity
{
    public int Id { get; set; }

    [NotMapped]
    public string NotMapped { get; set; }
}

创建一个拦截器并重载它的方法之一(我选择了InitializedInstance):

class NotMappedValueGeneratingInterceptor : IMaterializationInterceptor
{
    public static NotMappedValueGeneratingInterceptor Instance = new ();
    public object InitializedInstance(MaterializationInterceptionData materializationData, object entity)
    {
        if (entity is MyEntity my)
        {
            var valueProvider = materializationData.Context.GetService<IValueProvider>();
            my.NotMapped = valueProvider.GetValue();
        }
        
        return entity;
    }
}

并使用我们的 DI 方法将拦截器添加到上下文设置中AddDbContext更改为:

serviceCollection.AddDbContext<SomeContext>(builder => 
    builder.UseSqlite($"Filename={nameof(SomeContext)}.db")
       .AddInterceptors(NotMappedValueGeneratingInterceptor.Instance));
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从 EF Core 加载时计算 NotMapped 属性 的相关文章

  • 结构化绑定中缺少类型信息

    我刚刚了解了 C 中的结构化绑定 但有一件事我不喜欢 auto x y some func is that auto正在隐藏类型x and y 我得抬头看看some func的声明来了解类型x and y 或者 我可以写 T1 x T2 y
  • 如何将 std::string& 转换为 C# 引用字符串

    我正在尝试将 C 函数转换为std string参考C 我的 API 如下所示 void GetStringDemo std string str 理想情况下 我希望在 C 中看到类似的东西 void GetStringDemoWrap r
  • 调用 McAfee 病毒扫描引擎

    我收到客户的请求 要求使用他们服务器上的 McAfee 病毒扫描将病毒扫描集成到应用程序中 我做了一些调查 发现 McScan32 dll 是主要的扫描引擎 它导出各种看起来有用的函数 我还发现提到了 McAfee Scan Engine
  • 通过引用传递 [C++]、[Qt]

    我写了这样的东西 class Storage public Storage QString key const int value const void add item QString int private QMap
  • C++11 删除重写方法

    Preface 这是一个关于最佳实践的问题 涉及 C 11 中引入的删除运算符的新含义 当应用于覆盖继承父类的虚拟方法的子类时 背景 根据标准 引用的第一个用例是明确禁止调用某些类型的函数 否则转换将是隐式的 例如最新版本第 8 4 3 节
  • free 和 malloc 在 C 中如何工作?

    我试图弄清楚如果我尝试 从中间 释放指针会发生什么 例如 看下面的代码 char ptr char malloc 10 sizeof char for char i 0 i lt 10 i ptr i i 10 ptr ptr ptr pt
  • 传递给函数时多维数组的指针类型是什么? [复制]

    这个问题在这里已经有答案了 我在大学课堂上学习了 C 语言和指针 除了多维数组和指针之间的相似性之外 我认为我已经很好地掌握了这个概念 我认为由于所有数组 甚至多维 都存储在连续内存中 因此您可以安全地将其转换为int 假设给定的数组是in
  • 从经典 ASP 调用 .Net C# DLL 方法

    我正在开发一个经典的 asp 项目 该项目需要将字符串发送到 DLL DLL 会将其序列化并发送到 Zebra 热敏打印机 我已经构建了我的 DLL 并使用它注册了regasm其次是 代码库这使得 IIS 能够识别它 虽然我可以设置我的对象
  • 用于 FTP 的文件系统观察器

    我怎样才能实现FileSystemWatcherFTP 位置 在 C 中 这个想法是 每当 FTP 位置添加任何内容时 我都希望将其复制到我的本地计算机 任何想法都会有所帮助 这是我之前问题的后续使用 NET 进行选择性 FTP 下载 ht
  • 需要帮助优化算法 - 两百万以下所有素数的总和

    我正在尝试做一个欧拉计划 http projecteuler net问题 我正在寻找 2 000 000 以下所有素数的总和 这就是我所拥有的 int main int argc char argv unsigned long int su
  • ASP.NET Core 3.1登录后如何获取用户信息

    我试图在登录 ASP NET Core 3 1 后获取用户信息 如姓名 电子邮件 id 等信息 这是我在登录操作中的代码 var claims new List
  • WcfSvcHost 的跨域异常

    对于另一个跨域问题 我深表歉意 我一整天都在与这个问题作斗争 现在已经到了沸腾的地步 我有一个 Silverlight 应用程序项目 SLApp1 一个用于托管 Silverlight SLApp1 Web 的 Web 项目和 WCF 项目
  • C# 动态/expando 对象的深度/嵌套/递归合并

    我需要在 C 中 合并 2 个动态对象 我在 stackexchange 上找到的所有内容仅涵盖非递归合并 但我正在寻找能够进行递归或深度合并的东西 非常类似于jQuery 的 extend obj1 obj2 http api jquer
  • 复制目录下所有文件

    如何将一个目录中的所有内容复制到另一个目录而不循环遍历每个文件 你不能 两者都不Directory http msdn microsoft com en us library system io directory aspx nor Dir
  • 如何在 Linq to SQL 中使用distinct 和 group by

    我正在尝试将以下 sql 转换为 Linq 2 SQL select groupId count distinct userId from processroundissueinstance group by groupId 这是我的代码
  • 编译时展开 for 循环内的模板参数?

    维基百科 here http en wikipedia org wiki Template metaprogramming Compile time code optimization 给出了 for 循环的编译时展开 我想知道我们是否可以
  • 有没有办法让 doxygen 自动处理未记录的 C 代码?

    通常它会忽略未记录的 C 文件 但我想测试 Callgraph 功能 例如 您知道在不更改 C 文件的情况下解决此问题的方法吗 设置变量EXTRACT ALL YES在你的 Doxyfile 中
  • 在 WPF 中使用 ReactiveUI 提供长时间运行命令反馈的正确方法

    我有一个 C WPF NET 4 5 应用程序 用户将用它来打开某些文件 然后 应用程序将经历很多动作 读取文件 通过许多插件和解析器传递它 这些文件可能相当大 gt 100MB 因此这可能需要一段时间 我想让用户了解 UI 中发生的情况
  • 使用特定参数从 SQL 数据库填充组合框

    我在使用参数从 sql server 获取特定值时遇到问题 任何人都可以解释一下为什么它在 winfom 上工作但在 wpf 上不起作用以及我如何修复它 我的代码 private void UpdateItems COMBOBOX1 Ite
  • C# 中最小化字符串长度

    我想减少字符串的长度 喜欢 这串 string foo Lorem ipsum dolor sit amet consectetur adipiscing elit Aenean in vehicula nulla Phasellus li

随机推荐