简体   繁体   English

EF Core:域中没有导航属性的一对多关系

[英]EF Core: One to many relationship without navigation property in domain

Hi good people of Internet :)嗨,互联网的好人:)
I am trying to use EF Core 5 entities as domain entities in a sense of DDD.我正在尝试将 EF Core 5 实体用作 DDD 意义上的域实体。

I have a case of two entities, each with their own identity (meaning they are Entity type of DDD objects, not ValueObjects): Country and Currency.我有两个实体的案例,每个实体都有自己的身份(意味着它们是 DDD 对象的实体类型,而不是 ValueObjects):国家和货币。

Currency can belong to many Countries (for example EUR).货币可以属于多个国家(例如欧元)。 Country, on the other hand, can have only one 'currently active' Currency, which isn't necessarily the same Currency at all times (such example would be EU country, abandoning their own national currency for the EUR).另一方面,国家/地区只能有一种“当前有效”的货币,这不一定是始终相同的货币(例如,欧盟国家/地区放弃自己的本国货币以换取欧元)。

In a specific domain bounded context, I would need only:在特定的域有界上下文中,我只需要:

public class Country : Entity<Guid>
{
    public string Name { get; private set; }
    // the rest is omitted for readability
    public Currency Currency { get; private set; }
}

and

public class Currency : Entity<Guid>
{
    public string Name { get; set; }
    public string Code { get; set; }
}

I don't want to have navigation property: public ICollection<Country> Countries { get; private set; }我不想拥有导航属性: public ICollection<Country> Countries { get; private set; } public ICollection<Country> Countries { get; private set; } public ICollection<Country> Countries { get; private set; } on the Currency entity, just to be able to define 1:N relationship, because this would only pollute my domain. public ICollection<Country> Countries { get; private set; }对货币的实体,只是为了能够定义1:N的关系,因为这只会污染我的域名。

I tried to add navigation property as EF shadow property, but EF doesn't allow it, with thrown exception:我试图将导航属性添加为 EF 阴影属性,但 EF 不允许它,抛出异常:

The navigation 'Countries' cannot be added to the entity type 'Currency' because there is no corresponding CLR property on the underlying type and navigations properties cannot be added in shadow state.导航“国家/地区”无法添加到实体类型“货币”,因为基础类型上没有对应的 CLR 属性,并且无法在阴影状态下添加导航属性。

Currency can't be owned (in a EF sense as OwnsOne) by Country, because that would mean that Currency would have to have composite {Id, IdCountry} PK in the database, which would violate the requirement of being able to assign one currency to multiple countries.国家不能拥有货币(在 EF 意义上为 OwnsOne),因为这意味着货币必须在数据库中具有复合 {Id, IdCountry} PK,这将违反能够分配一种货币的要求到多个国家。

Is there a solution to establish a relationship between Currency and Country (or the other way around), which doesn't pollute the domain with navigation property and allows the same CLR object to be used as a domain and EF entity?是否有解决方案可以在货币和国家/地区(或其他方式)之间建立关系,该关系不会使用导航属性污染域并允许将相同的 CLR 对象用作域和 EF 实体?

I am trying to use EF Core 5 entities as domain entities in a sense of DDD.我正在尝试将 EF Core 5 实体用作 DDD 意义上的域实体。

EF entities represent the so called data model, which in general is different from domain/business model, has its own requirements/modelling rules which are different from the other models, and navigation properties are great relationship representation which allow producing different type of queries without using manual joins etc. EF 实体代表所谓的数据模型,它通常与域/业务模型不同,有自己的需求/建模规则,与其他模型不同,导航属性是很好的关系表示,允许生成不同类型的查询而无需使用手动连接等。

So in general you should use separate models and map between the two where needed, thus not "polluting" your domain mode or breaking its rules.因此,通常您应该使用单独的模型并在需要时在两者之间进行映射,从而不会“污染”您的域模式或违反其规则。 Simply the same way you follow the domain model rules, you should follow the data model rules - I don't understand why the people think EF should follow their rules rather than they following EF rules.就像您遵循域模型规则一样,您应该遵循数据模型规则 - 我不明白为什么人们认为 EF 应该遵循他们的规则而不是遵循 EF 规则。


Anyway, with that being said, while super useful, EF Core navigation properties are not mandatory (except currently for many-to-many via implicit junction entity and skip navigations) - you can have both, just principal, just dependent or even neither ends.无论如何,话虽如此,虽然非常有用,但 EF Core 导航属性不是强制性的(除了目前通过隐式连接实体和跳过导航的多对多) - 您可以同时拥有两者,只是主体,只是依赖或什至都没有结束.

All you need is to define the relationship with the proper Has / With pair.您所需要的只是定义与正确的Has / With对的关系。 Proper means to use pass the navigation property when exists, and omit it when it doesn't.正确意味着在存在时使用传递导航属性,并在不存在时省略它。

It this case, you could use something like this:在这种情况下,你可以使用这样的东西:

modelBuilder.Entity<Country>()
    .HasOne(e => e.Currency) // reference navigation property
    .WithMany() // no collection navigation property
    .IsRequired(); // omit this for optional relationship (to allow null FK)

The same can be achieved if you start the configuration from the other side.如果从另一端开始配置,也可以达到同样的效果。 Just in that case you have to provide explicitly the generic type argument since it cannot be inferred automatically:在这种情况下,您必须明确提供泛型类型参数,因为它无法自动推断:

modelBuilder.Entity<Currency>()
    .HasMany<Country>() // no collection navigation property
    .HasOne(e => e.Currency) // reference navigation property
    .IsRequired(); // omit this for optional relationship (to allow null FK)

You can use either way, just don't do both, since it is one and the same relationship, hence should be configured only once to avoid conflicting configurations (in case one is using separate IEnityTypeConfiguration<TEntity> classes which don't really fit well with relationships - one relationship with two ends).您可以使用任何一种方式,只是不要同时使用两者,因为它是同一个关系,因此应该只配置一次以避免配置冲突(如果使用单独的IEnityTypeConfiguration<TEntity>类并不真正适合关系很好 - 一种关系有两端)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM