[英]LINQ join failing between table and list of objects
我需要使用 C# .NET Core 3.0 中的對象列表中的值對表執行更新。 我嘗試使用 Join 方法,但收到此錯誤:
LINQ 表達式的處理
DbSet<Room>.Join( outer: __p_0, inner: p => p.RoomId, outerKeySelector: s => s.ruId, innerKeySelector: (s, p) => new { kuku = s, riku = p })
'NavigationExpandingExpressionVisitor' 失敗。 這可能表示 EF Core 中的錯誤或限制。 有關更多詳細信息,請參閱鏈接。
public class Room
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Key]
public int RoomId { get; set; }
[StringLength(50, MinimumLength = 3)]
public string RoomAddress { get; set; }
}
public class roomsForUpdate
{
public int ruId { get; set; }
public string ruName { get; set; }
}
var roomList = new List<roomsForUpdate>() { new roomsForUpdate { ruId = 1, ruName = "aa" }, new roomsForUpdate { ruId = 2, ruName = "bb" } };
var result = _context.Room.Join(roomList, p => p.RoomId, s => s.ruId, (s, p) => new { kuku = s, riku = p }).ToList();
您不能將 EF Core LINQ 查詢與本地列表相結合,因為它無法轉換為 SQL。 最好先獲取數據庫數據,然后加入 memory。
LINQ 並不是要更改源,它只能從源中提取數據。 如果需要更新數據,首先獲取必須更新的項目,然后更新它們。 或者,您可以使用普通的舊 SQL 來更新數據,而無需先獲取數據。
在本地 memory 中,您有一個RoomsForUpdate
序列。 每個 RoomForUpdate 都有一個 Id (RuId) 和一個名稱。
在您的數據庫中,您有一個帶有Rooms
的表,該表中的每個Room
在RoomId
中都有一個 Id 和一個RoomAddress
。
在我看來,您想要更新所有具有RoomId
的Rooms
,這是您的RuIds
序列中的 RuId 之一。 換句話說:獲取具有 RoomId 值的所有房間(的某些屬性),該值是您的 RoomsForUpdate 序列中的 RuId:
var roomsToUpdate = new List<roomsForUpdate>()
{
new roomsForUpdate { ruId = 1, ruName = "aa" },
new roomsForUpdate { ruId = 2, ruName = "bb" }
};
// Extract the Ids of the rooms that must be fetched
var roomToUpdateIds = roomsToUpdate.Select(room => room.ruId);
// Fetch all rooms from the database that have a RoomId that is in this sequence
var fetchedRooms = dbContext.Rooms
.Where(room => roomToUpdateIds.Contains(room => room.RoomId)
.ToList();
當然,您可以將所有內容放入一個大的 LINQ 語句中。 這不會提高效率,但是會降低代碼的可讀性。
現在要更新房間,您必須一一枚舉它們,並為獲取的房間賦予新值。 你沒有說你想要哪個新值。 我有一個暗示,您想將 RuName 分配給 RoomAddress。 這意味着您必須將 Room 與 RoomAddress 的新值結合起來。
這可以通過 LINQ 完成:
var roomsWithExpectedNewValues = fetchedRooms.Join(roomsToUpdate,
fetchedRoom => fetchedRoom.RoomId, // from every fetched room take the Id
roomToUpdate => roomToUpdate.RuId, // from every room to update take the RuId
// for every fetchedRoom with its matching room to update, make one new:
(fetchedRoom, roomToUpdate) => new
{
Room = fetchedRoom,
NewValue = roomToUpdate.RuName,
})
.ToList();
要實際執行更新,您必須枚舉此序列:
foreach (var itemToUpdate in roomsWithExpectedNewValues)
{
// assign RuName to RoomName
itemToUpdate.Room.RoomName = itemToUpdate.NewValue;
}
dbContext.SaveChanges();
雖然這有效,但似乎有很多魔法正在發生。 聯接將在內部創建一個字典以進行快速查找,然后將其丟棄。 我認為少一點 LINQ 會更容易理解發生了什么。
// your original roomsToUpdate
var roomsToUpdate = new List<roomsForUpdate>()
{
new roomsForUpdate { ruId = 1, ruName = "aa" },
new roomsForUpdate { ruId = 2, ruName = "bb" }
};
var updateDictionary = roomsToUpdate.ToDictionary(
room => room.RuId, // key
room => room.RuName) // value
字典的鍵是您要獲取的房間的 ID:
// fetch the rooms that must be updated:
var fetchedRooms = dbContext.Rooms
.Where(room => updateDictionary.Keys.Contains(room => room.RoomId)
.ToList();
// Update:
foreach (var fetchedRoom in fetchedRooms)
{
// from the dictionary fetch the ruName:
var ruName = updateDicationary[fetchedRoom.RoomId];
// assign the ruName to RoomAddress
fetchedRoom.RoomAddress = ruName;
// or if you want, do this in one statement:
fetchedRoom.RoomAddress = updateDicationary[fetchedRoom.RoomId];
}
dbContext.SaveChanges();
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.