【问题标题】:Owned type mapping EF Core fails when saving保存时拥有的类型映射 EF Core 失败
【发布时间】:2021-07-24 20:38:44
【问题描述】:

我想使用 Owned Types 制作 TableSplitting。我有以下型号:

public class Account 
{
  public GUID Id { get; set; }
  public string Email { get; set; }
  public StreetAddress Address { get; set; }
}

public class StreetAddress
{
  public string Name { get; set; }
  public string Address { get; set; }
  public string Zipcode { get; set; }
  public string City { get; set; }
  public string  Country { get; set; }
  public Location Location { get; set; }
}

public class Location
{
  public double Lat { get; set; }
  public double Lng { get; set; }
}

我这样定义了我的帐户映射:

public override void Map(EntityTypeBuilder<Account> map)
{
    // Keys
    map.HasKey(x => x.Id);

    // Indexs
    map.HasIndex(x => x.Email).IsUnique();

    // Property mappings.
    map.Property(x => x.Email).HasMaxLength(255).IsRequired();

    // Owned types.
    map.OwnsOne(x => x.Address, cb => cb.OwnsOne(a => a.Location));
}

当我运行迁移时,一切正常,并且在数据库中创建了列。但是当我尝试插入并保存这样的地址时:

var account1 = new Account("e@mail.com", "First", "Last")
    {
      Address = new StreetAddress()
                  {
                        Address1 = "Street 1",
                        City = "City",
                        Zipcode = "2000",
                        Country = "Denmark",
                        Location = new Location()
                        {
                            Lat = 0.0,
                            Lng = 5.5
                        }

                    }
                };
this.Context.Accounts.Add(account1);

我收到此错误

消息“'Account' 的实体与表 'Accounts' 共享 'Account.Address#StreetAddress',但没有这种类型的实体 具有相同的键值 'Id:b7662057-44c2-4f3f-2cf0-08d504db1849' 已被标记为“已添加”。”

【问题讨论】:

  • 它对我有用。你确定你调用了Map 显示的方法吗?因为只有当我不调用它时,我才会收到有问题的错误。
  • @Edit :根据文档,它应该按照约定添加。并且应该不需要主键,因为字段都应该进入已定义主键的 Account 表中 - 还是我弄错了?
  • @IvanStoev -> 我很确定 - 但我会检查一下以确认。
  • OwnedType 不支持与所有者在同一个表中映射的可选(即可为空)拥有类型(即使用表拆分)。我建议你看这个帖子github.com/aspnet/EntityFramework.Docs/issues/466
  • 查看此文档:Owned Entity Types

标签: c# .net-core entity-framework-core


【解决方案1】:

考虑使用虚拟属性。这也可以用于您的应用程序中的延迟加载

 public class Account 
 {
  public GUID Id { get; set; }
  public string Email { get; set; }
  public virtual StreetAddress Address { get; set; }
 }

public class StreetAddress
{
  public string Name { get; set; }
  public string Address { get; set; }
  public string Zipcode { get; set; }
  public string City { get; set; }
  public string  Country { get; set; }
  public virtual Location Location { get; set; }
}

public class Location
{
  public double Lat { get; set; }
  public double Lng { get; set; }
}

【讨论】:

    【解决方案2】:

    您必须添加构造函数并初始化拥有的实体。

    public class Account 
    {
      public Account (){
        Address = new StreetAddress();
      }
    
      public GUID Id { get; set; }
      public string Email { get; set; }
      public StreetAddress Address { get; set; }
    }
    
    public class StreetAddress
    {
      public StreetAddress(){
        Location = new Location();
      }
    
      public string Name { get; set; }
      public string Address { get; set; }
      public string Zipcode { get; set; }
      public string City { get; set; }
      public string  Country { get; set; }
      public Location Location { get; set; }
    }
    
    public class Location
    {
      public double Lat { get; set; }
      public double Lng { get; set; }
    }
    

    换句话说,不能有可选的拥有实体。

    注意:如果你有一个非空构造函数,你还必须添加空构造函数,因为ef core limitations.

    【讨论】:

    • 如果您默认初始化属性,则不需要构造函数,例如公共街道地址地址 { 获取;放; } = 新街道地址();
    【解决方案3】:
    public class Account {
      public GUID Id { get; set; }
      public string Email { get; set; }
      public StreetAddress Address { get; set; }
    }
    
    public class StreetAddress {
      public string Name { get; set; }
      public string Address { get; set; }
      public string Zipcode { get; set; }
      public string City { get; set; }
      public string  Country { get; set; }
      public Location[] Location { get; set; }
    
    
    public class Location {
      public double Lat { get; set; }
      public double Lng { get; set; }
    }
    

    试试这个,因为一旦你以所有的形式调用你的对象,它就与 Account 类有关,但现实是你没有定义我所做的那种关系

    【讨论】:

      【解决方案4】:

      用于将帐户添加到数据库中。它的引用应首先保存在表中。要在数据库中添加数据,应按以下顺序:位置 > 街道地址 > 帐户

      【讨论】:

        【解决方案5】:

        我敢肯定,如果您尝试将每个对象添加到上下文中,然后构建父对象,它将起作用 意思是先添加位置,然后创建地址并引用你创建的位置对象 将地址添加到上下文中 之后创建帐户并引用其中添加的地址!

        或者您可以将 ctor 添加到您的模型中,以初始化每个导航属性的新实例

        最后一件事,这确实不应该成为 EF Core 5 的问题,因为它在导航属性方面有很多新的花里胡哨

        public override void Map(EntityTypeBuilder<Account> map)
        {
            // Keys
            map.HasKey(x => x.Id);
        
            // Indexs
            map.HasIndex(x => x.Email).IsUnique();
        
            // Property mappings.
            map.Property(x => x.Email).HasMaxLength(255).IsRequired();
        
            // Owned types.
            map.OwnsOne(x => x.Address, cb => cb.OwnsOne(a => a.Location));
        }
        

        如果你正在使用它,你真的不需要以下部分 只需适当地添加您的DbSet&lt;T&gt;s 就可以了

        【讨论】:

          猜你喜欢
          • 2018-08-28
          • 2020-03-19
          • 1970-01-01
          • 1970-01-01
          • 2021-04-28
          • 1970-01-01
          • 2017-03-17
          • 1970-01-01
          • 2020-05-03
          相关资源
          最近更新 更多