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