首页 > 解决方案 > EF Code First 将外键插入/更新限制为给定的 ReferenceType

问题描述

对 EF Code First 来说相当新,并试图锻炼如何做我通常用触发器做的事情。我想创建一个参考表,其中包含给定系统中不同下拉列表和选择框的各种项目。参考表布局如​​下:

    ReferenceId     Guid
    ReferenceType   string
    Key             string
    value           object

我想为状态代码、性别类型、用户提出的任何多项选择等项目存储键/值。在允许插入/更新之前,我想在不同的表上设置一个外键,以便在引用表中存在键/值。我过去在 Database First SQL 中通过创建外键然后添加触发器来限制属于特定 ReferenceType 的允许键/值来完成此操作。

据我所知,您没有使用 EF Code First 的触发器,所以我想我需要检查给定表的外键 id 属性的 set 方法,以确保该值是给定的ReferenceType 在引用表中,如果没有则抛出异常。我正在考虑引用表模型中的一个方法,另一个表模型中的 set 方法可以调用传递 ReferenceType 和 Key,如果有效,则返回 ReferenceId,否则返回 null 并引发异常。

我的问题是,这是否是处理此类情况的正确方法,或者 EF 中是否有另一种我没有看到的方法来执行此操作?

目前为 Net Core 2.2 编码

标签: entity-framework.net-coreef-code-first

解决方案


通过使用自定义验证属性弄清楚了。发现我需要同时覆盖SaveChanges()SaveChangesAsync()在我的 DBContext 中。添加了对以下方法的调用:

        private void ValidateEntities()
        {
            var entities = (from entry in ChangeTracker.Entries()
                            where entry.State == EntityState.Modified || entry.State == EntityState.Added
                            select entry.Entity);

            var validationResults = new List<ValidationResult>();
            foreach (var entity in entities)
            {
                var validationContext = new ValidationContext(entity);
                Validator.ValidateObject(entity, validationContext, true);
            }
        }

这使我可以申请以下ValidationAttribute课程:

using System;
using System.ComponentModel.DataAnnotations;
using DataAccess.Models;

namespace DataAccess.Data.Attributes
{
    /// <summary>
    /// Valid Reference Attribute
    /// </summary>
    /// <revision>
    /// __Revisions:__~~
    /// | Contributor | Build | Revison Date | Description |~
    /// |-------------|-------|--------------|-------------|~
    /// | Christopher D. Cavell | 0.3.0 | 09/16/2019 | Initial commit |~ 
    /// </revision>
    public sealed class ValidGenderTypeAttribute : ValidationAttribute
    {
        private Guid validGuid = Constants.GenderTypeId; 

        /// <summary>
        /// Validate ReferenceTypeId
        /// </summary>
        /// <param name="value">object</param>
        /// <param name="validationContext">ValidationContext</param>
        /// <returns>ValidationResult</returns>
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            if (value != null)
            {
                if (value is Reference)
                {
                    Reference reference  = (Reference)value;

                    if (reference.ReferenceTypeId == validGuid)
                        return ValidationResult.Success;

                    return new ValidationResult($"Invalid GenderTypeID: {reference.ReferenceTypeId.ToString()}");  
                }
                return new ValidationResult($"Invalid object type: {value.GetType().ToString()}");
            }
            return ValidationResult.Success;
        }
    }
}

像这样对我的模型:

        /// <value>Guid</value>
        public Guid? GenderId { get; set; }

        /// <value>Reference</value>
        [ForeignKey("GenderId")]
===>    [ValidGenderType]
        public Reference Gender { get; set; }

推荐阅读