首页 > 解决方案 > 实体框架 6 -> 具有多个键的通用 DbSet.Find 方法

问题描述

我正在编写一个应用程序,我们在其中调用 20 多个 API 来使用实体框架在我们的数据库中添加或更新值。模型可以具有在 1-6 个属性之间变化的键。我已经为 Add 或 Update 编写了一个通用方法以避免重复代码,但我坚持DbSet.Find()使用几个键动态调用。如果每个模型都具有相同数量的键,那将不是问题,但不幸的是,情况并非如此。

示例模型:

public class TPClassification
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public Classifications ClassificationId { get; set; }

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

    public bool IsCyclical { get; set; }

    [MaxLength(400)]
    public string Comment { get; set; }
}

public class TPFeeCalculation
{
    [Key, Column(Order = 0)]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    [MaxLength(15)]
    public string BusinessSystemId { get; set; }

    [Key, Column(Order = 1)]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int CaseId { get; set; }

    [ForeignKey("BusinessSystemId,CaseId")]
    public virtual TPCase TPCase { get; set; }

    [Key, Column(Order = 2)]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    [MaxLength(5)]
    public string Action { get; set; }

    [Key, Column(Order = 3)]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int Cycle { get; set; }

    [ForeignKey("BusinessSystemId,CaseId,Action,Cycle")]
    public virtual TPRenewalCycle TPRenewalCycle { get; set; }

    [Key, Column(Order = 4)]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int RateNo { get; set; }

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

API 调用:

public ICollection<TPFeeCalculation> GetFeeCalculation(string businessSystemId, int caseId)
{
    var url = $"/api/feecalculations/{businessSystemId}/{caseId}";
    var result = GetRequest<ICollection<TPFeeCalculation>>(url);
    return result;
}

public ICollection<TPClassification> GetClassifications()
{
    var url = $"/api/classifications/";
    var result = GetRequest<ICollection<TPClassification>>(url);
    return result;
}

AddOrUpdate 方法:

// All methods could be called like this but it will result in a lof of code that is nearly duplicated
//internal void AddOrUpdateClassifications()
//{
//    var result = _IntegrationApiService.GetClassifications();
//
//    //foreach (var value in result)
//    //{
//    //    try
//    //    {
//    //        var current = _DbContext.Classifications.Find(value.ClassificationId);
//    //        if (current == null)
//    //        {
//    //            _DbContext.Classifications.Add(value);
//    //        }
//    //        else
//    //        {
//    //            _DbContext.Entry(current).CurrentValues.SetValues(value);
//    //        }
//    //    }
//    //    catch (Exception e)
//    //    {
//    //        throw;
//    //    }
//    //}
//    //_DbContext.SaveChanges();
//}

internal void AddOrUpdateClassifications()
{
    var result = _IntegrationApiService.GetClassifications();
    GenericAddOrUpdate(result, "ClassificationId");
}

internal void AddOrUpdateFeeCalculations(string businessSystemId, int caseId)
{
    var result = _IntegrationApiService.GetFeeCalculation(businessSystemId, caseId);
    //This does not work
    //GenericAddOrUpdate(result, "BusinessSystemId", "CaseId", "Action", "Cycle", "RateNo");
}

private void GenericAddOrUpdate<T>(ICollection<T> values, params string[] keyValues) where T : class 
{
    foreach (var value in values)
    {
        try
        {
            var keyList = new List<object>();

            foreach (var keyValue in keyValues)
            {
                var propertyInfo = value.GetType().GetProperty(keyValue);
                var propertyValue = propertyInfo.GetValue(value);
                keyList.Add(propertyValue);
            }

            var someDbSet = _DbContext.Set(typeof(T));
            //I need to add all the values from keyList here. I can't add the list directly since I will get the error below. Example with keyList[0] to show working code
            //The specified parameter type 'System.Collections.Generic.List`1[[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, //PublicKeyToken=b77a5c561934e089]]' is not valid. Only scalar types, such as System.Int32, System.Decimal, System.DateTime, and System.Guid, are supported.
            var current = someDbSet.Find(keyList[0]);
            if (current == null)
            {
                someDbSet.Add(value);
            }
            else
            {
                _DbContext.Entry(current).CurrentValues.SetValues(value);
            }
        }
        catch (Exception e)
        {
            throw;
        }
    }
    _DbContext.SaveChanges();
}

标签: c#entity-frameworkgenericsentity-framework-6

解决方案


推荐阅读