我们正在使用代码优先实体开发业务应用程序 框架,我正在寻找以下问题的解决方案 如果可能,它将不在数据库中。
我们有一个类似于以下内容的持久性模型:
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;
}
}
这对于将FamilyCode
和CommonCode
以及一些逻辑扩展到单个ModelOptionVersion
记录(foreach Model in Family...
)非常有用。但是,让我感到困惑的是如何将一组ModelOptionVersion
条记录返回与FamilyCode
或CommonCode
代表进行最佳匹配。
如果这是福特(不是),数据可能如下所示:
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年燃气发动机卡车”定价。他们不仅希望在创建价格记录时以这种方式看到它,而是在他们回去看之后再看它。因此,我需要一种不仅可以展开FamilyCode
和DataCode
成员,还可以将其展开的方法。但从数据来看,数据来源并不一定明显。此外,该系统应足够智能,当有人说“这只适用于F-250和F-350”时,系统会说“使用SuperDuty”。
在我看来,我需要某种最佳匹配解决方案,也许是一些轻量级的模糊逻辑。这样的.NET库是否存在?我是否必须从头开始制作?我怎样才能做到这一点?
答案 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();