我有一個真正的代碼優先部署我的數據模型,我需要執行通常會關聯到視圖的功能,但我不知道如何在時刻。在實體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