在c#

时间:2015-08-05 19:56:32

标签: c#

  

我们正在使用代码优先实体开发业务应用程序   框架,我正在寻找以下问题的解决方案   如果可能,它将不在数据库中。

我们有一个类似于以下内容的持久性模型:

public abstract class DataCode
{
   public long Id { get; set; }
   public string Code { get; set; }
   public string Description { get; set; }
}

public class Option : DataCode
{
   // a bunch of stuff that describes an Option
}

public class Model : DataCode
{
   // a bunch of stuff that describes a product model
}

public class Version
{
   public long Id { get; set; }
   // a bunch of stuff that describes a version of the product model
}

public class ModelOptionVersion
{
   public Model ThisModel { get; set; }
   public Option WithThisOption { get; set; }
   public Version UsingThisVersion { get; set; }
   // a bunch of stuff that is important to track 
   // at the intersection of these three properties
}

一切正常,但用户希望使用“家庭代码”和“公共代码”来应用属性值。为了支持这一点,我认为以下课程将起作用:

public abstract class CodeGroup
{
   public virtual ICollection<DataCode> DataCodes { get; set; }
}

public class Family : CodeGroup, DataCode
{
   public Family(ICollection<Model> Models)
   {
      base:DataCodes = Models;
   }
}

public class CommonCode : CodeGroup, DataCode
{
   public Family(ICollection<Option> Options)
   {
      base:DataCodes = Options;
   }
}

这对于将FamilyCodeCommonCode以及一些逻辑扩展到单个ModelOptionVersion记录(foreach Model in Family...)非常有用。但是,让我感到困惑的是如何将一组ModelOptionVersion条记录返回FamilyCodeCommonCode代表进行最佳匹配。

如果这是福特(不是),数据可能如下所示:

Family    | Model
Trucks    | F-150
Trucks    | F-250
Trucks    | F-350
SuperDuty | F-250
SuperDuty | F-350

CommonCode     | Option
Gas Engines    | 4.6l V-8 Gas
Gas Engines    | 5.4l V-8 Gas
Diesel Engines | 6.4l V-8 Diesel
Diesel Engines | 7.3l V-8 Diesel
Diesel Engines | 6.0l V-8 Diesel

Model | Option          | Version
F-150 | 4.6l V-8 Gas    | 2015
F-150 | 4.6l V-8 Gas    | 2016
F-150 | 5.4l V-8 Gas    | 2015
F-150 | 5.4l V-8 Gas    | 2016
F-250 | 5.4l V-8 Gas    | 2015
F-250 | 5.4l V-8 Gas    | 2016
F-350 | 5.4l V-8 Gas    | 2015
F-350 | 5.4l V-8 Gas    | 2016
F-250 | 6.4l V-8 Diesel | 2015
F-250 | 6.4l V-8 Diesel | 2016
F-350 | 6.4l V-8 Diesel | 2015
F-350 | 6.4l V-8 Diesel | 2016

用户希望根据“柴油发动机超级责任”或“2016年燃气发动机卡车”定价。他们不仅希望在创建价格记录时以这种方式看到它,而是在他们回去看之后再看它。因此,我需要一种不仅可以展开FamilyCodeDataCode成员,还可以将其展开的方法。但从数据来看,数据来源并不一定明显。此外,该系统应足够智能,当有人说“这只适用于F-250和F-350”时,系统会说“使用SuperDuty”。

在我看来,我需要某种最佳匹配解决方案,也许是一些轻量级的模糊逻辑。这样的.NET库是否存在?我是否必须从头开始制作?我怎样才能做到这一点?

1 个答案:

答案 0 :(得分:1)

  

然而,让我感到困惑的是如何最好地匹配一组   ModelOptionVersion记录回FamilyCode或CommonCode   代表。

您要在此处尝试查找FamilyCodes(或CommonCodes),以便某些集合中的每个ModelOptionVersion都具有该FamilyCode指定的模型。

var desiredModels = // some collection of Models

var familyCodesByFamily = (
    from familyCode in db.FamilyCodes
    group familyCode by familyCode.Family into family
    select family);

var applicableFamilies = (
    from family in familyCodesByFamily
    where desiredModels.All(dm => family.Any(f=> f.Model == dm))
    select family.Key).ToList();

我还没有测量过这种查询的执行方式,但它没有直接映射到SQL可以执行的操作。 SQL并没有直接让你做通用量词(“给我x对所有x,y”),但它确实让你做存在量词(“给我x这样存在y”)和否定。如果事实证明上述情况表现不佳,那么应该在语义上等同的替代方案是:

var incorrectFamilies = 
    (from familyCode in db.FamilyCodes
    where !desiredModels.Contains(familyCode.Model)
    select familyCode.Family).Distinct();

var correctFamilies =
    (from familyCode in db.FamilyCodes
    where !incorrectFamilies.Contains(familyCode.Model)
    select familyCode.Family).Distinct().ToList();

这些生成不同的SQL,自然看似第一种替代方案提供比第二种方案更复杂的SQL。无论您选择哪种样式,CommonCode的代码都应遵循相同的模板。

编辑:对于真正的模糊匹配,让我们开发两个度量来衡量一组模型和族之间的匹配程度。我们称之为“覆盖范围”的第一个(也是更重要的)措施,涉及家庭中包含的模型数量。第二个我们称之为“适合”,这与家庭中有多少成员包含在一组模型中(如果你有两个家庭,两个家庭都完全包含所需的模型,我们希望家庭拥有更少的额外超出我们期望的模型)。我们将通过匹配的优点来订购我们的结果,然后获取我们可以处理的结果数量。

var fuzzyFamilies = (
    from family in familyCodesByFamily
    let coverage = desiredModels.Average(dm => family.Any(f => f.Model == dm) ? 1.0 : 0.0)
    let fit = family.Average(f => desiredModels.Contains(f.Model) ? 1.0 : 0.0)
    orderby coverage descending, fit descending
    select family.Key)
    .Take(resultCount)
    .ToList();