实体框架核心2.1-拥有的类型和嵌套值对象 [英] Entity Framework Core 2.1 - owned types and nested value objects

查看:137
本文介绍了实体框架核心2.1-拥有的类型和嵌套值对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习DDD,并且当前正在使用的教程是使用NHibernate实现的,但是由于缺乏经验,我决定使用EF Core 2.1来完成本课程.

I'm learning DDD and the tutorial I'm currently following is implemented using NHibernate, but since my lack of experience with it I've decided to go through the course using EF Core 2.1.

但是,我目前对以下内容有些困惑:我有三个类Customer,这是一个实体和两个值对象(CustomerStatus及其内部的值对象ExpirationDate)-像这样:

However, I'm currently a bit stuck with the following: I have three classes Customer which is an entity and two value objects (CustomerStatus and inside of it value object ExpirationDate) - like this:

public class Customer : Entity
{
    //... constructor, other properties and behavior omitted for the sake of simplicity
    public CustomerStatus Status { get; set; }
}

public class CustomerStatus : ValueObject<CustomerStatus>
{
    // customer status is enum containing two values (Regular,Advanced)
    public CustomerStatusType Type { get; }
    public ExpirationDate ExpirationDate { get; }
}

public class ExpirationDate : ValueObject<ExpirationDate>
{
    //... constructor, other properties and behavior omitted for the sake of simplicity
    public DateTime? Date { get; private set; }
}

当我尝试在DbContext内部执行以下操作时:

When I try to do the following inside of my DbContext:

modelBuilder.Entity<Customer>(table =>
{      
   table.OwnsOne(x => x.Status,
     name =>
     {
        name.Property(x => x.ExpirationDate.Date).HasColumnName("StatusExpirationDate");
        name.Property(x => x.Type).HasColumnName("Status");
     });
});

我遇到以下错误:

表达式'x => x.ExpirationDate.Date'不是有效的属性表达式.该表达式应表示一个简单的属性访问:'t => t.MyProperty'.
参数名称:propertyAccessExpression'

The expression 'x => x.ExpirationDate.Date' is not a valid property expression. The expression should represent a simple property access: 't => t.MyProperty'.
Parameter name: propertyAccessExpression'

除此之外,我还尝试做类似的事情:

Beside this I've tried doing things like:

table.OwnsOne(x => x.Status.ExpirationDate,
      name =>
      {
         name.Property(x => x.Date).HasColumnName("StatusExpirationDate");
      });
 table.OwnsOne(x => x.Status,
      name =>
      {
          name.Property(x => x.Type).HasColumnName("Status");
      });

但这也会导致:

表达式'x => x.Status.ExpirationDate'不是有效的属性表达式.该表达式应表示一个简单的属性访问:"t => t.MyProperty".

The expression 'x => x.Status.ExpirationDate' is not a valid property expression. The expression should represent a simple property access: 't => t.MyProperty'.

我也尝试过:

modelBuilder.Entity<Customer>()
                    .OwnsOne(p => p.Status, 
              cb => cb.OwnsOne(c => c.ExpirationDate));

但是也没有运气...无论如何,任何帮助将不胜感激,如果可能的话,如果有人能够解释为什么我的尝试都没有奏效的话,那将是非常伟大的?提前致谢!

But with no luck as well... Anyways, any help would be greatly appreciated, also if possible it would be really great if someone could explain why none of my tries are not working? Thanks in advance!

更新

首先按照Ivan的评论所述进行操作后,我发现有关CustomerStatus类构造函数的错误,因此我添加了默认受保护的类.

After doing as stated in Ivan's comment first I was getting error about CustomerStatus class constructor so I've added default protected one.

此后,我开始出现错误:

After that I started getting error:

实体类型"CustomerStatus"的字段"k__BackingField"是只读的,因此无法设置.

Field 'k__BackingField' of entity type 'CustomerStatus' is readonly and so cannot be set.

在我的CustomerStatus类的内部,如果有帮助的话:

Here's inner of my CustomerStatus class if it helps:

public class CustomerStatus : ValueObject<CustomerStatus>
{
    public CustomerStatusType Type { get; }
    public ExpirationDate ExpirationDate { get; }

    public static readonly CustomerStatus Regular =
        new CustomerStatus(CustomerStatusType.Regular, ExpirationDate.Infinite);
    public bool IsAdvanced => Type == CustomerStatusType.Advanced && !ExpirationDate.IsExpired;

    private CustomerStatus(CustomerStatusType type, ExpirationDate expirationDate)
    {
        Type = type;
        ExpirationDate = expirationDate;
    }

    protected CustomerStatus()
    {

    }
    public static CustomerStatus Create(CustomerStatusType type, ExpirationDate expirationDate)
    {
        return new CustomerStatus(type, expirationDate);
    }

    public CustomerStatus Promote()
    {
        return new CustomerStatus(CustomerStatusType.Advanced, ExpirationDate.Create(DateTime.UtcNow.AddYears(1)).Value);
    }

    protected override bool EqualsCore(CustomerStatus other)
    {
        return Type == other.Type && ExpirationDate == other.ExpirationDate;

    }

    protected override int GetHashCodeCore()
    {
        return Type.GetHashCode() ^ ExpirationDate.GetHashCode();
    }
}

更新

所要做的就是在CustomerStatus类内部的TypeExpirationDate属性上添加私有设置器,并与Ivan的答案结合使用,就像一个魅力.非常感谢!

All it took was adding private setters on Type and ExpirationDate properties inside of CustomerStatus class and in combination with Ivan's answer it works like a charm. Thanks a lot!

推荐答案

您的尝试不起作用,因为只能通过其 owner 实体配置所有类型,具体来说,是通过自己的由OwnsOne方法返回的构建器,或作为所有者实体构建器的OwnsOne方法的Action<T>自变量的自变量提供的.

Your attempts are not working because owned types can only be configured through their owner entity, and more specifically, through their own builder returned by the OwnsOne method or provided as an argument of the Action<T> argument of the OwnsOne method of the owner entity builder.

因此配置应如下所示(请注意嵌套的OwnsOne):

So the configuration should be something like this (note the nested OwnsOne):

modelBuilder.Entity<Customer>(customer =>
{      
    customer.OwnsOne(e => e.Status, status =>
    {
        status.Property(e => e.Type).HasColumnName("Status");
        status.OwnsOne(e => e.ExpirationDate, expirationDate =>
        {
            expirationDate.Property(e => e.Date).HasColumnName("StatusExpirationDate");
        });
    });
});

这篇关于实体框架核心2.1-拥有的类型和嵌套值对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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