Entity Framework 非必填对象字段验证错误

Entity Framework validation error on non-required object field

我有一个 ASP.NET MVC 网站,它正在将 ViewModel 传递给 WebAPI 服务,以便首先使用 Entity Framework 代码对数据库中的对象执行 CRUD 操作。

我的域实体对象之一是企业,它具有企业信息、地址、主要联系人和次要联系人。问题是,不需要次要联系人对象,因为并非所有公司都会有次要联系人。我已将 ID 字段设置为可为 null,但当我尝试将新业务记录保存到没有辅助联系人对象的数据库时,它给我实体验证错误,表明辅助联系人记录字段是必需的。

有谁知道如何停止这个错误,这样我就可以在没有第二联系人的情况下将业务实体保存在数据库中?

下面是相关代码。我正在使用自动映射器在我的视图模型和模型之间进行映射。

域业务对象

    public class Business
{
    public Guid PrimaryContactId { get; set; }
    [ForeignKey("PrimaryContactId")]
    [Required]
    public virtual Contact PrimaryContact { get; set; }

    public Guid? SecondaryContactId { get; set; }
    [ForeignKey("SecondaryContactId")]
    public virtual Contact SecondaryContact { get; set; }

    [Key]
    public Guid Id { get; set; }

    [Required]
    [MaxLength(100)]
    public string CompanyName { get; set; }

    [MaxLength(100)]
    public string CompanyWebsite { get; set; }

    [Required]
    [MaxLength(100)]
    public string Industry { get; set; }

    [Required]
    public NumberOfEmployees NumberOfEmployees { get; set; }

    [Required]
    public CommunicationPreference CommunicationPreference { get; set; }

    public Guid AddressId { get; set; }

    [ForeignKey("AddressId")]
    [Required]
    public virtual Address Address { get; set; }
}

业务视图模型

public class BusinessViewModel
{
    public Guid PrimaryContactId { get; set; }
    public PrimaryContactViewModel PrimaryContact { get; set; }

    public Guid? SecondaryContactId { get; set; }
    public SecondaryContactViewModel SecondaryContact { get; set; }

    public Guid Id { get; set; }

    [DisplayName("Company Name")]
    [Required]
    [MinLength(3, ErrorMessage = "Your {0} must be at least {1} characters long")]
    [MaxLength(100, ErrorMessage = "Your {0} must be no more than {1} characters")]
    public string CompanyName { get; set; }

    [DisplayName("Company Website")]
    [MinLength(3, ErrorMessage = "Your {0} must be at least {1} characters long")]
    [MaxLength(100, ErrorMessage = "Your {0} must be no more than {1} characters")]
    public string CompanyWebsite { get; set; }

    [DisplayName("Industry")]
    [Required]
    [MinLength(3, ErrorMessage = "Your {0} must be at least {1} characters long")]
    [MaxLength(100, ErrorMessage = "Your {0} must be no more than {1} characters")]
    public string Industry { get; set; }

    [DisplayName("Number of Employees")]
    [Required]
    public NumberOfEmployees NumberOfEmployees { get; set; }

    [DisplayName("Communication Preference")]
    [Required]
    public CommunicationPreference CommunicationPreference { get; set; }

    public Guid AddressId { get; set; }
    [Required]
    public AddressViewModel Address { get; set; }
}

域联系人对象

    public class Contact
{
    [Key]
    public Guid Id { get; set; }

    [Required]
    public Salutations? Prefix { get; set; }

    [Required]
    [MaxLength(100)]
    public string FirstName { get; set; }

    [Required]
    [MaxLength(100)]
    public string LastName { get; set; }

    [Required]
    [MaxLength(100)]
    public string JobTitle { get; set; }

    [Required]
    [DataType(DataType.EmailAddress)]
    [MaxLength(100)]
    public string Email { get; set; }

    [Required]
    [MaxLength(100)]
    public string Phone { get; set; }

    [MaxLength(100)]
    public string PhoneExtension { get; set; }
}

基本联系人视图模型

    public class BaseContactViewModel
{
    public Guid Id { get; set; }

    [DisplayName("Primary Contact Prefix")]
    public virtual Salutations Prefix { get; set; }

    [DisplayName("Primary Contact First Name")]
    [MinLength(3, ErrorMessage = "Your {0} must be at least {1} characters long")]
    [MaxLength(100, ErrorMessage = "Your {0} must be no more than {1} characters")]
    public virtual string FirstName { get; set; }

    [DisplayName("Primary Contact Last Name")]
    [MinLength(3, ErrorMessage = "Your {0} must be at least {1} characters long")]
    [MaxLength(100, ErrorMessage = "Your {0} must be no more than {1} characters")]
    public virtual string LastName { get; set; }

    [DisplayName("Primary Contact Job Title")]
    [MinLength(3, ErrorMessage = "Your {0} must be at least {1} characters long")]
    [MaxLength(100, ErrorMessage = "Your {0} must be no more than {1} characters")]
    public virtual string JobTitle { get; set; }

    [DisplayName("Primary Contact Email Address")]
    [DataType(DataType.EmailAddress)]
    [MinLength(3, ErrorMessage = "Your {0} must be at least {1} characters long")]
    [MaxLength(100, ErrorMessage = "Your {0} must be no more than {1} characters")]
    public virtual string Email { get; set; }

    [DisplayName("Primary Contact Phone")]
    [DataType(DataType.PhoneNumber)]
    [MinLength(3, ErrorMessage = "Your {0} must be at least {1} characters long")]
    [MaxLength(100, ErrorMessage = "Your {0} must be no more than {1} characters")]
    public virtual string Phone { get; set; }

    [DisplayName("Primary Contact Extension")]
    [MinLength(3, ErrorMessage = "Your {0} must be at least {1} characters long")]
    [MaxLength(100, ErrorMessage = "Your {0} must be no more than {1} characters")]
    public virtual string PhoneExtension { get; set; }
}

辅助联系人视图模型

public class SecondaryContactViewModel : BaseContactViewModel
{

    [DisplayName("Secondary Contact Prefix")]
    public override Salutations Prefix { get; set; }

    [DisplayName("Secondary Contact First Name")]
    public override string FirstName { get; set; }

    [DisplayName("Secondary Contact Last Name")]
    public override string LastName { get; set; }

    [DisplayName("Secondary Contact Job Title")]
    public override string JobTitle { get; set; }

    [DisplayName("Secondary Contact Email Address")]
    public override string Email { get; set; }

    [DisplayName("Secondary Contact Phone")]
    public override string Phone { get; set; }

    [DisplayName("Secondary Contact Extension")]
    public override string PhoneExtension { get; set; }

}

节省EF的方法

public async Task<bool> CreateBusinessAsync(BusinessViewModel businessViewModel)
    {
        try
        {
            // TODO: Move mapping to some common place?
            Mapper.CreateMap<BusinessViewModel, Business>();
            Mapper.CreateMap<BaseContactViewModel, Contact>();
            Mapper.CreateMap<AddressViewModel, Address>();


            Business business = Mapper.Map<Business>(businessViewModel);

            //TODO: See why EntityFramework isn't automatically putting in GUIDs
            business.Id = Guid.NewGuid();
            business.Address.Id = Guid.NewGuid();
            business.PrimaryContact.Id = Guid.NewGuid();


            // Attach the objects so they aren't saved as new entries
            db.States.Attach(business.Address.State);
            db.Countries.Attach(business.Address.Country);

            //TODO: See why entity framework isn't automatically saving records
            var bus = db.Businesses.Add(business);
            var primary = db.Contacts.Add(business.PrimaryContact);

            if (!String.IsNullOrEmpty(business.SecondaryContact.FirstName))
            {
                business.SecondaryContact.Id = Guid.NewGuid();
                db.Contacts.Add(business.SecondaryContact);
            }
            else
            {
                business.SecondaryContact = null;
            }


            var address = db.Addresses.Add(business.Address);

            int rowsAffected = await db.SaveChangesAsync();


            if (bus != null && rowsAffected > 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        catch (Exception e)
        {
            //TODO: Add exception logger
            string error = e.Message;

            return false;
        }

    }

请告诉我看看其他 类 是否有用。谢谢。

我之前遇到过类似的问题,我解决它的方法是从 属性 中删除外键数据注释并使用 fluent-api。使用 fluent-api 我只是将关系的正确一侧标记为可选。

您可以根据文档将数据类型设置为可为空

public class Foo {
// ...... Some property
[ForeignKey("tagId")]
public ICollection<SomeModel>? data {get; set;}
}

这将使 属性 未验证和 return 验证结果。使用 Model.IsValid