IMutableEntityType.GetProperties()不包含我想要的属性 [英] IMutableEntityType.GetProperties() doesn't include a property that I want

查看:92
本文介绍了IMutableEntityType.GetProperties()不包含我想要的属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一堆模型,它们都利用了我创建的类.它们具有类型 Measurement 的属性.这个 Measurement 类本身不是要映射到数据库表的实体或模型.它只是一种用于成对传递值和单位的类型,还有一堆用于管理对这些值和单位的操作的方法和运算符.

I have a bunch of models that all make use of a class that I have created. They have properties of type Measurement. This Measurement class is not in itself an entity or a model that I want mapped to a database table. It's simply a type for passing around values and units in a pair, along with a bunch of methods and operators for managing operations on those values and units.

我创建了一个 ValueConverter ,以便可以在模型中将这种类型的属性表示为数据库中的字符串.

I have created a ValueConverter so that I can represent the properties of this type in my models as strings in the database.

ValueConverter<Measurement, string> measurementConverter = new ValueConverter<Measurement, string>
(
    v => v.ToString(),
    v => new Measurement(v)
);

然后,我的计划是,在我的 DbContext 中的 OnModelCreating()方法中,遍历我的所有实体及其属性,并使用 property.如果它们是 Measurement 类型,则在它们上设置SetValueConverter(measurementConverter); .这样,模型中的所有Measurements都将自动能够保存到数据库并从数据库中加载,并且我不必在模型中保留额外的字符串表示字段.

Then, my plan is, in the OnModelCreating() method in my DbContext, to loop over all my entities and their properties, and use property.SetValueConverter(measurementConverter); on them if they are of the Measurement type. This way, all the Measurements in my models will automatically be able to save to and load from the database, and I don't have to keep extra string representation fields in my models.

这是我正在谈论的循环:

Here's the loop I'm talking about:

foreach (var entity in modelBuilder.Model.GetEntityTypes())
{
    foreach (var property in entity.GetProperties())
    {
        if(property.ClrType == typeof(Measurement)) { property.SetValueConverter(measurementConverter); }
    }
}

问题出在 GetProperties()方法上.它的文档摘要说:

The problem lies with the GetProperties() method. The documentation summary for it says this:

此API仅返回标量属性,不返回导航属性

This API only returns scalar properties and does not return navigation properties

其结果是,我的 Measurement 属性完全没有返回.我相信Entity Framework认为 Measurement 类实际上是其自己的模型,因此它不会像对待普通属性那样对待它.当然,这意味着 ValueConverter 永远不会设置在它上面,并且整个解决方案都无法按照我想要的方式工作.

The result of that is that none of my Measurement properties are returned by it at all. I believe that Entity Framework thinks that the Measurement class is actually its own model, so it doesn't treat it like a normal property. Of course, this means that the ValueConverter is never set on it and the whole solution doesn't work the way I want it to.

我的第一个想法是将 Measurement 类改为一个结构,因为它已经是不可变的,并且没有真正的理由为什么它不能最初是一个结构.难道不是让Entity Framework清楚这是一个标量属性,应该包含在 GetProperties()返回中吗?我是这么认为的,但显然不是.更改后,我仍然得到相同的行为.

My first thought was to turn the Measurement class into a struct instead, as it is already immutable and there's no real reason why it couldn't have been a struct in the first place. Wouldn't that make it clear to Entity Framework that this is a scalar property and should be included in the GetProperties() return? I thought so, but apparently not. I still get the same behavior after changing it.

我想避免在每个模型的每个 Measurement 属性上放置一个属性,因此,如果有什么方法可以告诉Entity Framework所有这些属性实际上都是可绑定的,那真是太棒了.如果没有,那我该如何标记它们呢?

I would like to avoid putting an attribute on every Measurement property in every model, so if there's any way to just tell Entity Framework that all of these properties are in fact bindable, that would be awesome. If not, then how do I mark them out?

谢谢.

推荐答案

令人讨厌的是,EF Core当前没有提供映射用户定义类型的好方法.NET拓扑套件使用了一种插件机制,有点需要太多管道代码.

It's annoying that EF Core currently does not provide a good way to map user defined types. There is a plugin mechanism which is used by NET Topology suite, bit it requires too much plumbing code.

因此, GetProperties 问题:

此API仅返回标量属性,不返回导航属性

This API only returns scalar properties and does not return navigation properties

好吧,一旦您知道EF Core将您的类型视为实体,因此将该类型的属性视为导航属性,则可以使用 GetNavigations 而不是 GetProperties :

Well, once you know that EF Core treats your type as entity, hence treats properties of that type as navigation properties, you can use GetNavigations instead of GetProperties:

foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
    foreach (var navigation in entityType.GetNavigations().ToList())
    {
        if (navigation.ClrType == typeof(Measurement))
        {
            var entityTypeBuilder = modelBuilder.Entity(entityType.ClrType);
            entityTypeBuilder
                .Property<Measurement>(navigation.Name)
                .HasConversion(measurementConverter);
        }
    }
}

唯一的问题是这个

var entityTypeBuilder = modelBuilder.Entity(entityType.ClrType);

我们在这里可以看到

As we can see here EF Core configuration problem with owned type used in 2 different classes, this is problematic (does not work) for owned entity types. And making it work requires using the internal API:

var entityTypeBuilder = new EntityTypeBuilder(entityType.AsEntityType().Builder);

在您自己的回答中,您说使用内部API是不好的".恕我直言,唯一的缺点是该库没有为此提供良好"的公共API.另一方面,幸运的是,所有内部" EF Core API都是公开可用的,并且在公共API不足的情况下可用于此类情况.唯一的区别是,在升级较新版本并进行相应更新时,您必须注意API的更改.考虑到它们破坏了公共API的次数,这不是什么大问题/关注点.

In your own answer you say that using the internal API is "bad". IMHO the only bad thing is that the library does not provide a "good" public API for that. From the other side, fortunately all "internal" EF Core APIs are publicly available and can be used for scenarios like this when the public API is not sufficient. The only difference is that you have to watch the API changes when upgrading the newer version and update accordingly. Considering how many times they break the public APIs, this should not be a big deal/concern.

这篇关于IMutableEntityType.GetProperties()不包含我想要的属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆