我在我的專案中使用 EF 6。我想要的只是從資料庫中獲取一些資料,有時加入額外的資料。
這是我的代碼:
var queryable = dbContext.Manuals
.AsNoTracking()
.Where(x => x.Status == "ACTIVE");
if (showDisabledParents)
{
var parentsIds = queryable
.Where(x => x.ParentId.HasValue)
.Select(x => x.ParentId.Value)
.Distinct()
.ToArray();
queryable = queryable.Union(
dbContext.Manuals
.AsNoTracking()
.Where(x => parentsIds.Contains(x.Id))
);
}
當showDisabledParents為false時效果很好。EF 將生成具有正確列名的 SQL 查詢。
但是當showDisabledParents為真時,EF 會生成 UNION 陳述句(這是預期的),但它使用 C1、C2、C3 ......作為列名。
問題是我有一個自定義DbDataReader如果列名以"Utc"結尾,它呼叫DateTime.SpecifyKind(..., DateTimeKind.Utc)。而且由于 EF 使用了錯誤的列名(C1、C2、C3、...),我的邏輯不起作用。
是否有可能阻止這種行為?我的意思是如果有辦法告訴 EF 不要使用這些奇怪的列名。
更新:這是我的 DBDataReaderCode:
public class MyDbDataReader : DelegatingDbDataReader
{
private string _dbName;
public MyDbDataReader(string dbName, DbDataReader source)
: base(source)
{
_dbName = dbName;
}
public override DateTime GetDateTime(int ordinal)
{
return DateTime.SpecifyKind(base.GetDateTime(ordinal), base.GetName(ordinal).EndsWith("UTC", StringComparison.OrdinalIgnoreCase)
? DateTimeKind.Utc
: DateTimeKind.Local);
}
}
uj5u.com熱心網友回復:
我用于處理 DateTime.Kind 的典型方法是在適用的物體屬性上使用屬性。例如,這將適用于 UTC 的任何 DateTime 物體屬性:
[DateTimeKind(DateTimeKind.Utc)]
public DateTime SomeDateUTC { get; set; }
如果您希望將其他日期時間標記為當地時間:
[DateTimeKind(DateTimeKind.Local)]
public DateTime SomeDate { get; set; }
沒有屬性的日期時間將保留為未指定型別。
屬性本身:參見(物體框架 DateTime 和 UTC)
然后在您的 DbContext 中,您只需將其添加到 InitializeContext 方法中:
((IObjectContextAdapter)this).ObjectContext.ObjectMaterialized =
(sender, e) => DateTimeKindAttribute.Apply(e.Entity);
否則,如果您想堅持使用當前方法并且依賴于列名,Union則無法計算,因此將條件拆分為兩個查詢。無論在何處執行查詢,都需要執行此操作,因此如果您的方法回傳一個IQueryable<Manual>,則需要將其更改為IEnumerable<IQueryable<Manual>>where 如果回傳多個查詢,則合并結果。
var queryables = new List<IQueryable<Manual>();
queryables.Add(dbContext.Manuals
.AsNoTracking()
.Where(x => x.Status == "ACTIVE"));
if (showDisabledParents)
{
var parentsIds = dbContext.Manuals
.Where(x => x.Status == "ACTIVE"
&& x.ParentId.HasValue)
.Select(x => x.ParentId.Value)
.Distinct()
.ToArray();
queryables.Add = dbContext.Manuals
.AsNoTracking()
.Where(x => parentsIds.Contains(x.Id));
}
return queryables;
如果您改為在此方法中執行查詢,則只需捕獲第二個查詢(如果需要)并組合要回傳的結果。
這里最棘手的一點是如果您需要跨組合集進行分頁。在這種情況下,我將改為使用兩遍方法,在適當排序后獲取相關任務 ID,然后對 ID 使用分頁獲取,按 ID 加載物體:
var queryable = dbContext.Manuals
.AsNoTracking()
.Where(x => x.Status == "ACTIVE");
if (showDisabledParents)
{
var parentsIds = queryable
.Where(x => x.ParentId.HasValue)
.Select(x => x.ParentId.Value)
.Distinct()
.ToArray();
queryable = queryable.Union(
dbContext.Manuals
.AsNoTracking()
.Where(x => parentsIds.Contains(x.Id))
);
}
var ids = queryable
.OrderBy(/* condition */)
.Select(x => x.Id)
.Skip(page * pageSize)
.Take(pageSize)
.ToList(); // Should execute union without worrying about column transformation since we have requested only IDs.
var manuals = await dbContext.Manuals.Where(x => ids.Contains(x.Id)).ToListAsync();
至少要考慮幾個選項。
uj5u.com熱心網友回復:
我認為這是不可能的,因為 EF 使用內部別名來生成整個查詢,并確保從不同表等收集的名稱中沒有重復。
無論如何,我寧愿搜索有關您處理日期的方法的問題。您能否提供有關您案件的更多詳細資訊?一般來說,經驗法則是始終將您的日期保留在 UTC 中,并根據需要轉換為特定時區。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/426629.html
