我有一个真正的代码优先部署我的数据模型,我需要执行通常会关联到视图的功能,但我不知道如何在时刻。在实体EF核心包含计算属性
为了简化问题,我的模型包含注册用户创建的内容以及其他用户可以与之交互的内容。我正在设计一个算法,说明这些东西是如何受欢迎的,这些算法归结为与交互类型相关的加权因子乘以某个日期时间的倒数。
举一个例子,假设我们有“喜欢”,“评论”和“购买”,权重分别为1,2和3。我们也说我的时间段是1周。在这种情况下,3周前购买的产品与当周的赞一样多。
所以模型的相关部分是Thing
它有一个主键和一些额外的元数据; InteractionType
,它有一个主键,一个Weight
值和一些其他元数据; Interaction
,其具有复合主键(由Thing
主键,User
对象主键和InteractionType
主键组成)和DateValue
列以及任何其他上下文相关的元数据。
最后,我想有一个实体框架来执行下面的查询兼容方式:
;WITH InteractionScore
AS
(
SELECT t.Id ThingId, SUM(it.Weight/CAST(DATEDIFF(wk, i.DateValue, GETDATE()) AS float)) IntScore
FROM Things t
INNER JOIN Interactions i ON t.Id = i.ThingId
INNER JOIN InteractionTypes it ON i.InteractionTypeId = it.Id
GROUP BY t.ID
)
SELECT TOP(10) t.*
FROM Things t
LEFT JOIN InteractionScore isc ON t.Id = isc.ThingId
ORDER BY ISNULL(isc.IntScore, 0.0) DESC
数据模型类的定义如下:
namespace Project.Entities
{
public class User
{
[Key]
public int Id {get; set;}
public string IdentityRef {get;set;}
public string DisplayName {get;set;}
[InverseProperty("Owner")]
public ICollection<Thing> OwnedThings {get; set;}
}
public class InteractionType
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public double Weight { get; set; }
}
public class Thing
{
[Key]
public int Id {get;set;}
public int OwnerId {get; set;}
[ForeignKey("OwnerId")]
public User Owner {get; set;}
public string Summary {get; set;}
public string Description {get; set;}
public ICollection<Interaction> Interactions {get;set;}
}
public class Interaction
{
public int ThingId { get; set; }
public int UserId { get; set; }
public int InteractionTypeId {get; set;}
public Thing Thing {get; set;}
public User User {get;set;}
public InteractionType InteractionType {get;set;}
public DateTime DateValue {get;set;}
public string Comment {get; set;}
public string PurchaseReference {get;set;}
}
}
在消费应用
的的DbContext定义namespace Project.Consumer
{
public class ApplicationData : DbContext
{
public DbSet<User> Users {get;set;}
public DbSet<Thing> Things {get;set;}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<Interaction>()
.HasKey(i => new {i.ThingId, i.UserId, i.InteractionTypeId});
}
}
public List<Thing> GetMostPopularThings(ApplicationData ctx)
{
return ctx.Things.OrderByDescending(lambdaMagic).Take(10).ToList();
}
}
lambdaMagic当然是snark,但是当我说,我不确定是否有文件记录的方式做到这一点,我只是想念它或什么。我已经看到选择按照ctx.Things.FromSql("select string or sp here").Take(10).ToList();
的方法做一些事情,这可能是好的,但我真的想减少项目之外存在的东西的数量(例如SP定义)
由于写了这个问题,我继续创建了另一个模型类叫做ThingStatistics:
public class ThingStatistics
{
[Key]
public int ThingId {get; set;}
[ForeignKey("ThingId")]
public Thing Thing {get; set;}
public double InteractionScore {get;set;}
}
然后我增强Thing类如下:
public class Thing
{
[Key]
public int Id {get;set;}
public int OwnerId {get; set;}
[ForeignKey("OwnerId")]
public User Owner {get; set;}
public string Summary {get; set;}
public string Description {get; set;}
public ICollection<Interaction> Interactions {get;set;}
public ThingStatistics Stats {get;set;}
}
我进行添加,迁移步骤,然后改变所产生的向上/向下的如下:
public partial class AggregationHack : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("GO; CREATE VIEW ThingStatistics AS SELECT t.ID ThingId, ISNULL(it.Weight/CAST(DATEDIFF(wk, i.DateValue, GETDATE()) + 1 AS float), 0) InteractionScore FROM Things t LEFT JOIN Interactions i INNER JOIN InteractionTypes it ON i.InteractionTypeId = it.Id ON t.ID = i.ThingId GROUP BY t.Id; GO;");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("DROP VIEW ThingStatistics; GO;");
}
}
所以,现在我能做的ctx.Things.Include(t => t.Stats).OrderByDescending(t => t.Stats.InteractionScore).Take(10).ToList()
和这样的作品,但我不知道这是否是正确的,因为它感觉像这样一个黑客...
_an实体框架兼容way_将涉及C#类上的一些C#代码。发布(简化)类开始。 –
@HenkHolterman,我添加了一些更多的上下文和一些广义的C#代码,让你知道我到目前为止的内容。谢谢参观。 – randcd