C# EntityFramework(存储库模式、数据验证、Dto和#x27;s)

C# EntityFramework(存储库模式、数据验证、Dto和#x27;s),c#,asp.net,entity-framework,rest,repository-pattern,C#,Asp.net,Entity Framework,Rest,Repository Pattern,我在整理如何使用EntityFramework创建Restful API时遇到了一些困难。这个问题主要是因为这个API应该长期使用,我希望它是可维护的、干净的、具有良好性能的。够了,让我们开始讨论这个问题 Disclamer: 因为公司政策,我不能在这里发布太多,但我会尽可能用最好的方式解决这个问题。还有一些代码片段,可能是无效的。我也是C#的新手,作为一名少年,我以前从未接触过API。。请原谅我的英语,这是我的第二语言 每个模型都源自基本模型类 public class BaseModel {

我在整理如何使用EntityFramework创建Restful API时遇到了一些困难。这个问题主要是因为这个API应该长期使用,我希望它是可维护的、干净的、具有良好性能的。够了,让我们开始讨论这个问题

Disclamer: 因为公司政策,我不能在这里发布太多,但我会尽可能用最好的方式解决这个问题。还有一些代码片段,可能是无效的。我也是C#的新手,作为一名少年,我以前从未接触过API。。请原谅我的英语,这是我的第二语言

每个模型都源自基本模型

public class BaseModel
{
    [Required]
    public Guid CompanyId { get; set; }

    public DateTime CreatedDateTime { get; set; }

    [StringLength(100)]
    public string CreatedBy { get; set; }

    public DateTime ChangedDateTime { get; set; }

    [StringLength(100)]
    public string ChangedBy { get; set; }

    public bool IsActive { get; set; } = true;

    public bool IsDeleted { get; set; }
}

public class Carrier : BaseModel
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [Key]
    public Guid CarrierId { get; set; }

    public int CarrierNumber { get; set; }

    [StringLength(100)]
    public string CarrierName { get; set; }

    [StringLength(100)]
    public string AddressLine { get; set; }

    public Guid? PostOfficeId { get; set; }
    public PostOffice PostOffice { get; set; }
    public Guid? CountryId { get; set; }
    public Country Country { get; set; }

    public List<CustomerCarrierLink> CustomerCarrierLinks { get; set; }
}
公共类基模型
{
[必需]
公共Guid公司ID{get;set;}
公共日期时间CreatedDateTime{get;set;}
[长度(100)]
通过{get;set;}创建的公共字符串
公共日期时间更改日期时间{get;set;}
[长度(100)]
公共字符串由{get;set;}更改
public bool IsActive{get;set;}=true;
公共布尔被删除{get;set;}
}
公共类运营商:BaseModel
{
[数据库生成(DatabaseGeneratedOption.Identity)]
[关键]
公共Guid载体ID{get;set;}
public int CarrierNumber{get;set;}
[长度(100)]
公共字符串载体名称{get;set;}
[长度(100)]
公共字符串地址行{get;set;}
公共Guid?PostOfficeId{get;set;}
公共邮政局邮政局{get;set;}
公共Guid?CountryId{get;set;}
公共国家{get;set;}
公共列表CustomerCarrierLinks{get;set;}
}
每个存储库都源于存储库,并有自己的接口

public class CarrierRepository : Repository<Carrier>, ICarrierRepository
{
    public CarrierRepository(CompanyMasterDataContext context, UnitOfWork unitOfWork) : base(context, unitOfWork) { }

    #region Helpers
    public override ObjectRequestResult<Carrier> Validate(Carrier carrier, List<string> errorMessages)
    {
        var errorMessages = new List<string>();

        if(carrier != null)
        {
            var carrierIdentifier = (carrier.CarrierName ?? carrier.CarrierNumber.ToString()) ?? carrier.CarrierGLN;

            if (string.IsNullOrWhiteSpace(carrier.CarrierName))
            {
                errorMessages.Add($"Carrier({carrierIdentifier}): Carrier name is null/empty");
            }
        }
        else
        {
            errorMessages.Add("Carrier: Cannot validate null value.");
        }

        return CreateObjectResultFromList(errorMessages, carrier); // nonsense
    }
公共类载体存储库:存储库,ICarrierRepository
{
公共载体存储库(CompanyMasterDataContext,UnitOfWork,UnitOfWork):基(context,UnitOfWork){}
#地区助手
公共覆盖ObjectRequestResult验证(承运人、列表错误消息)
{
var errorMessages=新列表();
如果(承运人!=null)
{
var carrierIdentifier=(carrier.CarrierName??carrier.CarrierNumber.ToString())??carrier.CarrierGLN;
if(string.IsNullOrWhiteSpace(carrier.CarrierName))
{
添加($”承运人({carrieriIdentifier}):承运人名称为空);
}
}
其他的
{
errorMessages.Add(“承运人:无法验证空值。”);
}
返回CreateObjectResultFromList(errorMessages,carrier);//无意义
}
}

UnitOfWork派生自UnitOfWorkDiscoverySet类,该类使用反射初始化存储库属性,还包含一个方法(OnBeforeChildEntityProcessed),用于调用每个OnBeforeChildEntityProcessed

public class UnitOfWork : UnitOfWorkDiscoverySet
{
    public UnitOfWork(CompanyMasterDataContext context) 
        : base(context){}

    public CarrierRepository Carriers { get; internal set; }
    public PostOfficeRepository PostOffices { get; internal set; }
    public CustomerCarrierLinkRepository CustomerCarrierLinks { get; internal set; }
}


public IRepository<Entity> where Entity : BaseModel
{
ObjectRequestResult<Entity> Add(Entity entity);
ObjectRequestResult<Entity> Update(Entity entity);
ObjectRequestResult<Entity> Delete(Entity entity);
ObjectRequestResult<Entity> Validate(Entity entity);
Entity GetById(Guid id);
Guid GetEntityId(Entity entity);
}

public abstract class Repository<Entity> : IRepository<Entity> where Entity : BaseModel
{
    protected CompanyMasterDataContext _context;
    protected UnitOfWork _unitOfWork;

    public Repository(CompanyMasterDataContext context, UnitOfWork unitOfWork)
    {
        _context = context;
        _unitOfWork = unitOfWork;
    }

    public ObjectRequestResult<Entity> Add(Entity entity)
    {
        if (!EntityExist(GetEntityId(entity)))
        {
            try
            {
                var validationResult = Validate(entity);

                if (validationResult.IsSucceeded)
                {
                    _context.Add(entity);
                    _context.UpdateEntitiesByBaseModel(entity);
                    _context.SaveChanges();

                    return new ObjectRequestResult<Entity>()
                    {
                        ResultCode = ResultCode.Succceeded,
                        ResultObject = entity,
                        Message = OBJECT_ADDED
                    };
                }

                return validationResult;
            }
            catch (Exception exception)
            {
                return new ObjectRequestResult<Entity>()
                {
                    ResultCode = ResultCode.Failed,
                    ResultObject = entity,
                    Message = OBJECT_NOT_ADDED,
                    ErrorMessages = new List<string>()
                    {
                        exception?.Message,
                        exception?.InnerException?.Message
                    }
                };
            }
        }

        return Update(entity);
    }

    public virtual ObjectRequestResult Validate(Entity entity)
    {
        if(entity != null)
        {
            if(!CompanyExist(entity.CompanyId))
            {
                return EntitySentNoCompanyIdNotValid(entity); // nonsense
            }
        }

        return EntitySentWasNullBadValidation(entity); // nonsense
    }
}
公共类UnitOfWork:UnitOfWorkDiscoverySet
{
公共工作单元(CompanyMasterDataContext上下文)
:base(context){}
公共载波存储载波{get;内部集;}
邮政局邮政局{get;内部集合;}
公共CustomerCarrierLinkRepository CustomerCarrierLinks{get;internal set;}
}
公共IRepository,其中实体:BaseModel
{
ObjectRequestResult添加(实体);
ObjectRequestResult更新(实体);
ObjectRequestResult删除(实体);
ObjectRequestResult验证(实体);
实体GetById(Guid id);
Guid GetEntityId(实体);
}
公共抽象类存储库:IRepository其中实体:BaseModel
{
受保护的CompanyMasterDataContext\u上下文;
受保护的工作单元_工作单元;
公共存储库(CompanyMasterDataContext上下文、UnitOfWork UnitOfWork)
{
_上下文=上下文;
_unitOfWork=unitOfWork;
}
公共对象请求结果添加(实体)
{
如果(!EntityExist(GetEntityId(entity)))
{
尝试
{
var validationResult=验证(实体);
如果(validationResult.Issucceed)
{
_添加(实体);
_context.UpdateEntitiesByBaseModel(实体);
_SaveChanges();
返回新的ObjectRequestResult()
{
ResultCode=ResultCode.Succeed,
结果对象=实体,
消息=添加的对象
};
}
返回验证结果;
}
捕获(异常)
{
返回新的ObjectRequestResult()
{
ResultCode=ResultCode.Failed,
结果对象=实体,
消息=对象未添加,
ErrorMessages=新列表()
{
异常?消息,
异常?.InnerException?.Message
}
};
}
}
返回更新(实体);
}
公共虚拟对象请求结果验证(实体)
{
如果(实体!=null)
{
如果(!CompanyExist(entity.CompanyId))
{
返回EntitySentNoCompanyIdNotValid(实体);//无意义
}
}
返回EntitySentWasNullBadValidation(实体);//无意义
}
}
DbContext类:

public class CompanyMasterDataContext : DbContext {

public DbSet<PostOffice> PostOffices { get; set; }
public DbSet<Carrier> Carriers { get; set; }

public DbSet<Company> Companies { get; set; }
public DbSet<CustomerCarrierLink> CustomerCarrierLinks { get; set; }



public UnitOfWork Unit { get; internal set; }

public CompanyMasterDataContext(DbContextOptions<CompanyMasterDataContext> options)
    : base(options)
{
    Unit = new UnitOfWork(this);
}

public void UpdateEntitiesByBaseModel(BaseModel baseModel)
{
    foreach (var entry in ChangeTracker.Entries())
    {
        switch (entry.State)
        {
            case EntityState.Added:
                entry.CurrentValues["CompanyId"] = baseModel.CompanyId;
                entry.CurrentValues["CreatedDateTime"] = DateTime.Now;
                entry.CurrentValues["CreatedBy"] = baseModel.CreatedBy;
                entry.CurrentValues["IsDeleted"] = false;
                entry.CurrentValues["IsActive"] = true;
                Unit.OnBeforeChildEntityProcessed(entry.Entity, enumEntityProcessState.Add);
                break;

            case EntityState.Deleted:
                entry.State = EntityState.Modified;
                entry.CurrentValues["ChangedDateTime"] = DateTime.Now;
                entry.CurrentValues["ChangedBy"] = baseModel.ChangedBy;
                entry.CurrentValues["IsDeleted"] = true;
                Unit.OnBeforeChildEntityProcessed(entry.Entity, enumEntityProcessState.Delete);
                break;

            case EntityState.Modified:
                if (entry.Entity != null && entry.Entity.GetType() != typeof(Company))
                    entry.CurrentValues["CompanyId"] = baseModel.CompanyId;

                entry.CurrentValues["ChangedDateTime"] = DateTime.Now;
                entry.CurrentValues["ChangedBy"] = baseModel.ChangedBy;

                Unit.OnBeforeChildEntityProcessed(entry.Entity, enumEntityProcessState.Update);
                break;
        }
    }
}
公共类CompanyMasterDataContext:DbContext{
公共数据库集邮局{get;set;}
公共DbSet载波{get;set;}
公共数据库集公司{get;set;}
公共数据库集CustomerCarrierLinks{get;set;}
公共UnitOfWork单元{get;内部集合;}
上市公司MasterDataContext(DbContextOptions)
:基本(选项)
{
单位=新的工作单位(本);
}
public void UpdateEntitiesByBaseModel(BaseModel BaseMode
    public abstract class UnitOfWorkDiscoverySet
{
    private Dictionary<Type, object> Repositories { get; set; }
    private CompanyMasterDataContext _context;

    public UnitOfWorkDiscoverySet(CompanyMasterDataContext context)
    {
        _context = context;
        InitializeSets();
    }

    private void InitializeSets()
    {
        var discoverySetType = GetType();
        var discoverySetProperties = discoverySetType.GetProperties();

        Repositories = new Dictionary<Type, object>();

        foreach (var child in discoverySetProperties)
        {
            var childType = child.PropertyType;
            var repositoryType = childType.GetInterfaces()
                .Where( i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IRepository<>))
                .FirstOrDefault();

            if (repositoryType != null)
            {
                var repositoryModel = repositoryType.GenericTypeArguments.FirstOrDefault();

                if (repositoryModel != null)
                {
                    if (repositoryModel.IsSubclassOf(typeof(BaseModel)))
                    {
                        var repository = InitializeProperty(child); //var repository = child.GetValue(this);

                        if (repository != null)
                        {
                            Repositories.Add(repositoryModel, repository);
                        }
                    }
                }
            }
        }
    }

    private object InitializeProperty(PropertyInfo property)
    {
        if(property != null)
        {
            var instance = Activator.CreateInstance(property.PropertyType, new object[] {
                _context, this
            });

            if(instance != null)
            {
                property.SetValue(this, instance);
                return instance;
            }
        }

        return null;
    }

    public void OnBeforeChildEntityProcessed(object childObject, enumEntityProcessState processState)
    {
        if(childObject != null)
        {
            var repository = GetRepositoryByObject(childObject);
            var parameters = new object[] { childObject, processState };

            InvokeRepositoryMethod(repository, "OnBeforeEntityProcessed", parameters);
        }
    }

    public void ValidateChildren<Entity>(Entity entity, List<string> errorMessages) where Entity : BaseModel
    {
        var children = BaseModelUpdater.GetChildModels(entity);

        if(children != null)
        {
            foreach(var child in children)
            {
                if(child != null)
                {
                    if (child.GetType() == typeof(IEnumerable<>))
                    {
                        var list = (IEnumerable<object>) child;

                        if(list != null)
                        {
                            foreach (var childInList in list)
                            {
                                ValidateChild(childInList, errorMessages);
                            }
                        }
                    }

                    ValidateChild(child, errorMessages);
                }
            }
        }
    }

    public void ValidateChild(object childObject, List<string> errorMessages)
    {
        if(childObject != null)
        {
            var repository = GetRepositoryByObject(childObject);
            var parameters = new object[] { childObject, errorMessages };

            InvokeRepositoryMethod(repository, "Validate", parameters);
        }
    }

    public void InvokeRepositoryMethod(object repository, string methodName, object[] parameters)
    {
        if (repository != null)
        {
            var methodToInvoke = repository.GetType().GetMethod(methodName);
            var methods = repository.GetType().GetMethods().Where(x => x.Name == methodName);

            if (methodToInvoke != null)
            {
                methodToInvoke.Invoke(repository, parameters);
            }
        }
    }

    public object GetRepositoryByObject(object objectForRepository)
    {
        return Repositories?[objectForRepository.GetType()];
    }

    public object GetObject<Entity>(Type type, Entity entity) where Entity : BaseModel
    {
        var childObjects = BaseModelUpdater.GetChildModels(entity);

        foreach (var childObject in childObjects)
        {
            if (childObject.GetType().FullName == type.FullName)
            {
                return childObject;
            }
        }

        return null;
    }
}
IQueryable<TEntity> GetTEntities()
IQueryable<TEntity> GetTEntityById(id)
IQueryable<TRelatedEntity> GetTRelatedEntities()
TEntity CreateTEntity({all required properties/references})
void DeleteTEntity(entity)
TChildEntity CreateTChildEntity(TEntity, {all required properties/references})