2017-02-17 49 views
0

我试图使用实体框架NullableGuid但是当我试图提交我得到验证的消息,由于外键是空的变化,我有以下领域类,DomainType类有孩子DomainCustomField: -实体框架与可空指引?导致验证错误

DomainType.cs
public class DomainType 
{ 
    public Guid? Id 
    { 
     get; 
     set; 
    } 
    private IList<DomainCustomField> _domainCustomFields; 

    public string Name 
    { 
     get; 
     set; 
    } 

    public Guid? AccountId 
    { 
     get; 
     set; 
    } 

    public virtual IList<DomainCustomField> DomainCustomFields 
    { 
     get 
     { 
      return this._domainCustomFields; 
     } 
     set 
     { 
      this._domainCustomFields = value; 
     } 
    } 
} 

DomainCustomField.cs
public class DomainCustomField 
{ 
     public Guid? Id 
     { 
       get; 
       set; 
     } 
     public string Name 
     { 
      get; 
      set; 
     } 
     public Guid? DomainTypeId 
     { 
      get; 
      set; 
     } 
} 
下面

是映射: -

modelBuilder.Domain<DomainCustomField>().HasKey((DomainCustomField p) => new 
      { 
       p.Id, 
       p.DomainTypeId 
      }); 
      modelBuilder.Domain<DomainCustomField>() 
       .Property(p => p.Id) 
       .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 
      modelBuilder.Domain<DomainType>() 
       .HasMany(p => p.DomainCustomFields) 
       .WithRequired() 
       .HasForeignKey<Guid?>(x => x.DomainTypeId); 

下面是我尝试插入的示例代码。

DomainType domainType = new DomainType() 
     { 
      AccountId = customer.Id 
     }; 
     domainType.DomainCustomFields.Add(new DomainCustomField() 
     { 
      Name = "Test" 
     }); 
     Workspace.Add<DomainType>(domainType); 
     Workspace.CommitChanges(); 

错误: - 用于DomainTypeId验证错误需要

在相同的代码,如果我在ID变量正确地更改Guid?Guid然后其工作。我不知道如何处理nullableGuid。我是否需要在子引用中手动设置父键?那么如何在Guid的情况下正常工作?

注意: - 我使用的是Guid,因为我使用分布式数据库,其中id可以从多个源系统生成。 我使用Guid?,因为默认Guid生成00000000-0000-0000-0000-000000000000为空Guid它可以增加数据库大小。

+0

您试过了(在模型中添加导航属性'DomainType')'.HasOptional' - >'modelBuilder.Domain () .Property(p => p.Id) ..HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).HasOptional(p => p.DomainType).. HasForeignKey(x => x.DomainTypeId)' – Developer

+0

是的,我试过HasOptional。它不是那个问题。即使它们被链接,它也不会在子变量中设置父ID。 –

+0

这个错误对我来说很合理,可能在这里我完全错了。当你的主键是“空的”(不知道“可空”主键是如何工作的)时,EF可能没有为子集合设置正确的关系(因为父ID是空的)。 – Developer

回答

-1

您可以使用数据库的标准标识符。 GUID?作为字段存储在表中。

+0

请看看问题中提到的注释'默认Guid生成00000000-0000-0000-0000-000000000000为可以增长数据库大小的空Guid' –

+0

您不能为主键使用可为空的类型。主键和GUID使用整数类型?作为表中的一个字段。 – npsavin

0

该问题与Guid类型无关(int也会发生这种情况),但是实体中使用的属性类型的可空性与模型隐含的属性的实际可空性之间存在差异。

首先,EF要求PK是非空的。因此,DomainType.Id,DomainCustomField.IdDomainCustomField.DomainTypeId实际上是不可修改的(目前还不清楚为什么你在DomainCustomField的PK中包含DomainTypeId,它已经有独特的数据库生成Id,但这是另一回事)。

其次,DomainCustomField.DomainTypeId实际上不可为空,因为您已指定--FK关系配置的WithRequired()部分。

现在,EF尽力处理这些差异。如果查看生成的迁移,您将看到所有相关字段的相应数据库表列不可空。然而(没有什么是完美的,你知道)EF代码的某些部分无法处理这种差异,因此也是例外。

就这么说,始终保持模型属性的可空性与其实际的可空性同步。在你的情况下,这两个属性是不可空的(即Guid类型)。

P.S.怎么样我使用Guid?因为默认Guid生成00000000-0000-0000-0000-000000000000为空Guid它可以增加数据库大小。,我不知道你是什么意思。类属性的无关性与数据库大小无关,正如我已经提到的那样,这种设置的相应数据库表列不能为空。

另请注意,在您的示例中,您忘记设置新的DomainTypeId,您应该这样做,因为它不是自动生成的。

1

我会在我的回答中采取稍微不同的方法,并尝试告诉你如何改变以获得一个工作示例;

像有人指出的那样,唯一标识符不能为空,因此DomainType中的Id字段应为Guid。您还需要更改DomainCustomField中的Id字段。这些可能需要一个空的构造函数才能创建一个新的Guid。其次,您的其他对象Guid? DomainTypeId中的外键非常好,这可以保留,但如果它处于停留状态,您将需要更改您的配置。

在此块中,您已指定该属性是必需的?

modelBuilder.Domain<DomainType>() 
       .HasMany(p => p.DomainCustomFields) 
       .WithRequired() 
       .HasForeignKey<Guid?>(x => x.DomainTypeId); 

因此,简单地说它是可选的;

modelBuilder.Domain<DomainType>() 
       .HasMany(p => p.DomainCustomFields) 
       .WithOptional() 
       .HasForeignKey<Guid?>(x => x.DomainTypeId); 

这应该可以解决您的问题。任何问题都让我知道:)

+0

这是我今天的问题,我已经指定了Guid列作为可选项,但没有为上面的许多行提示,提醒我将其设置为WithOptional可以为我解决这个问题。 如果我有WithRequired,那么生成的sql将会很奇怪,并且它不会返回例如为空的guid。 guid = null。即使数据库有一些空的guid值,也会返回空列表。 – Andrew