У меня есть следующая схема базы данных SQL Server 2005:
CREATE TABLE Messages (
MessageID int,
Subject varchar(500),
Text varchar(max) NULL,
UserID NULL
)
Столбец «UserID», который может быть нулевым, является внешним ключом и связывается с таблицей
CREATE TABLE Users (
UserID int,
...
)
Теперь у меня есть несколько классов POCO с именами Message, User и т. Д., Которые я использую в следующем запросе:
public IList<Message> GetMessages(...) {
var q = (from m in dataContext.Messages.Include("User")
where ...
select m); // could call ToList(), but...
return (from m in q
select new Message {
ID = m.MessageID,
User = new User {
ID = m.User.UserID,
FirstName = m.User.FirstName,
...
}
}).ToList();
}
Теперь обратите внимание, что я советую структуре сущностей - используя Include ("Users") - загрузить пользователя, связанного с сообщением, если оно есть. Также обратите внимание, что я не вызываю ToList () после первого оператора LINQ. При этом из базы данных будут возвращены только указанные столбцы в списке проекций - в этом случае MessageID, UserID, FirstName.
В этом и заключается проблема - как только Entity Framework встречает сообщение с UserID == NULL, оно выдает исключение, говоря, что не может преобразоваться в Int32, поскольку значение БД равно NULL.
Если я изменю последние пару строк на
return (from m in q
select new Message {
ID = m.MessageID,
User = m.User == null ? null : new User {
ID = m.User.UserID,
...
}
}).ToList()
затем генерируется исключение NotSupportedException во время выполнения, сообщающее, что оно не может создать постоянный тип User, и поддерживаются только такие примитивы, как int, string, guid.
У кого-нибудь есть идеи, как с этим справиться, кроме материализации результатов сразу после первого утверждения и последующего использования проекции в памяти? Спасибо.