简体   繁体   English

遵循DDD方式如何更新EF Core 2.0拥有的实体?

[英]How to update EF Core 2.0 Owned Entities following a DDD aproach?

I've a project where I'm using Asp.Net Core 2.0 following a DDD approach. 我有一个项目在遵循DDD方法的情况下使用Asp.Net Core 2.0。 So, I have aggregate roots that owns entities and value objects which are configured as owned types, a new feature in EF Core 2.0. 因此,我拥有聚合的根,这些根拥有实体和值对象,这些对象和值对象被配置为拥有的类型,这是EF Core 2.0中的一项新功能。 I've added an example of such configuration to better clarify. 我添加了这样的配置示例以更好地阐明。

Domain: 域:

public class Address : ValueObject 
{
    public Address(string street, int number){
        Street = street;
        Number = number;
    }

    public string Street {get; private set;}
    public int Number {get; private set;}
}  
public class Company : AggregateRoot
{
    public Address Address {get; private set;}
    // Other properties...

    // Value objects are immutables so I'm only able to replace it with a new object.
    public void UpdateAddress(string street, int number){
        Address = new Address(street, number);
    }
    // Other methods...
}

EF Core Entity Configuration: EF核心实体配置:

internal class CompanyEntityTypeConfiguration : IEntityTypeConfiguration<Company>
{
    public void Configure(EntityTypeBuilder<Company> builder)
    {
        builder.HasKey(x => x.Id);
        builder.OwnsOne(x => x.Address);
    }
}

I'm retrieving a tracking entity from the database and when I try to update the AggregateRoot replacing a value object with a new one I get an exception saying that "another entity of the same type is already being tracked". 我正在从数据库中检索跟踪实体,当我尝试更新AggregateRoot并将其替换为一个新的值对象时,出现一个异常,提示“另一个相同类型的实体已被跟踪”。 The address is the entity being tracked. 地址是被跟踪的实体。

Therefore, the solution was to retrieve an untracked but I don't want to use this approach because it will make a full update in the database. 因此,解决方案是检索未跟踪的内容,但我不想使用此方法,因为它将在数据库中进行完整的更新。 So, how can I update a value object(owned entity) from an entity being tracked by Entity Framework 2.0? 那么,如何从Entity Framework 2.0跟踪的实体更新值对象(拥有的实体)?

I found a workaround when I was working with ef core 1.0.0. 使用ef core 1.0.0时,我找到了一种解决方法。 I could not find the reference again to put the link here and give the credits to the author but, in your case, the workaround would be like this: 我再也找不到参考资料来将链接放在此处,并感谢作者,但是,在您的情况下,解决方法如下:

DOMAIN : 领域

public class Address : ValueObject
    {
        public Address(string street, int number)
        {
            Street = street;
            Number = number;
        }

        public string Street { get; private set; }
        public int Number { get; private set; }


        #region Value object workaround
        public Address WithStreet(string value) => new Address(value, Number);

        public Address WithNumber(int value) => new Address(Street, value);
        #endregion
    }
    public class Company : AggregateRoot
    {

        #region public public Address Address { get; set; }
        [NotMapped]
        public Address Address { get; set; }

        //In the DbContext this property needs to be mapped with a column in a database
        private string Address_Street
        {
            get { return Address.Street; }
            set { Address = Address.WithStreet(value); }
        }

        //In the DbContext this property needs to be mapped with a column in a database
        private int Address_Number
        {
            get { return Address.Number; }
            set { Address = Address.WithNumber(value); }
        }
        #endregion


        // Other properties...

        // Value objects are immutables so I'm only able to replace it with a new object.
        public void UpdateAddress(string street, int number)
        {
            Address = new Address(street, number);
        }
        // Other methods...
    }

EF Core Entity Configuration: EF核心实体配置:

internal class CompanyEntityTypeConfiguration : IEntityTypeConfiguration<Company>
    {
        public void Configure(EntityTypeBuilder<Company> builder)
        {
            #region Address value object workaround
            builder.Property(typeof(string), "Address_Street").HasColumnName("Address_Street");
            builder.Property(typeof(int), "Address_Number").HasColumnName("Address_Number");
            #endregion
        }
    }

It is needed to override the SaveChanges() in your DbContext 需要重写DbContext中的SaveChanges()

DbContext: DbContext:

public class YourDbContext : DbContext
    {
        //yours DbSet<>

        protected override void OnModelCreating(ModelBuilder builder)
        {
            //yours EntityTypeConfiguration
        }

        /// <summary>
        /// Overridden for value object workaround
        /// </summary>
        /// <returns></returns>
        public override int SaveChanges()
        {
            foreach (var entry in ChangeTracker.Entries())
            {
                foreach (var pi in entry.Entity.GetType().GetProperties(BindingFlags.Instance | BindingFlags.NonPublic))
                {
                    entry.Property(pi.Name).CurrentValue = pi.GetValue(entry.Entity);
                }
            }
            return base.SaveChanges();
        }
    }

It would be nice if ef core 2.0 owned entities works like EF6.X complex types in order to implements DDD value objects. 如果ef core 2.0拥有的实体像EF6.X复杂类型那样工作,以实现DDD值对象,那将是很好的。 This workaround will demand some monkey job code but you will be able to apply DDD. 此解决方法将需要一些猴子作业代码,但您将能够应用DDD。

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

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