实体框架在三个表中提取 null
本文关键字:三个 提取 null 框架 实体 | 更新日期: 2023-09-27 18:18:37
我的数据库中有三个表。每个表都使用不同的实体类,代码:
public class Quizs
{
[Key]
public int QuizId { get; set; }
public string Title { get; set; }
public string Instructions { get; set; }
public string IsTimerEnabled { get; set; }
public virtual ICollection<Question> Questions { get; set; }
}
public class Question
{
[Key]
public int QuestionId { get; set; }
public virtual ICollection<Answers> Answers { get; set; }
public int RightAnswer { get; set; } // Key of Answers[]
public int QuestionType { get; set; } // 1 = One choise, 2 = Multiple Choise
public string Explantion { get; set; } // To appear after answering the question
public int MaxTime { get; set; } // In seconds
}
public class Answers
{
[Key]
public int asId { get; set; }
public int Id { get; set; }
public string Text { get; set; }
}
所以现在我需要将这三个表中的所有数据输出到 WebApi 页面。
下面是在控制器中提取数据的代码:
// GET api/QuizsData/
public IEnumerable<Quizs> Get()
{
return dba.Quiz.Include("Questions").Include("Questions.Answers").ToList();
}
这是我转到 API 路由时得到的:
{"消息":">发生错误。","异常消息":"无效列 名称"Question_QuestionId"。''r'列名无效 'Question_QuestionId'.","ExceptionType":"System.Data.SqlClient.SqlException","StackTrace":" at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, 布尔中断连接, 操作
1 wrapCloseInAction)'r'n at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action
1 包装关闭操作(''r'
在 System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose(''r'
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady(''r' at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData((''r' at System.Data.SqlClient.SqlDataReader.get_MetaData((''r' at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, 运行行为 运行行为, 字符串重置选项字符串(''r' at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite(''r' at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String 方法, TaskCompletionSource'1 completion, Int32 timeout, Task& task, 布尔异步写入(''r' at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String 方法(''r' 在 System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior 行为,字符串方法(''r' at System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior 行为(''r' 在 System.Data.Common.DbCommand.ExecuteReader(CommandBehavior 行为(''r' 在 System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommand(EntityCommand entityCommand, CommandBehavior behavior("}
我收到了这条异常消息..有什么帮助吗?
谢谢!
我不认为你已经按照你认为的方式建立了你的关系。
请尝试以下更改:
public class Quizs
{
// no attribute
public virtual ICollection<Question> Questions { get; set; }
}
public class Question
{
// no attribute
public virtual ICollection<Answers> Answers { get; set; }
// add
[ForeignKey("Quiz")]
public int QuizId { get; set; }
public virtual Quizs Quiz { get; set; }
}
public class Answers
{
// add
[ForeignKey("Question")]
public int QuestionId { get; set; }
public virtual Question Question { get; set; }
}
(此外,请考虑将类名转换为单数。这样可以减少语义混乱。
关于什么是什么的更多解释:
你在这里试图实现的被称为一对多关系。例如,您有许多问题指向一个测验。或者你有很多答案指向一个问题。在测验-问题关系中,测验是"一"面,问题是"多"方。在问答关系中,问题是"一"面,答案是"多"面。
要在实体框架中实现这样的关系,您所要做的就是转到关系的"多"端并添加如下所示的内容:
public virtual Quiz Quiz { get; set; }
然后转到关系的"一"端并添加如下内容:
public virtual ICollection<Question> Questions { get; set; }
实体框架理解第一个声明表示"创建表Quiz
的外键",另一个声明表示"Question
表的多个记录将指向此处"。
这就像普通类之间的关系一样,不同之处在于您将属性设置为虚拟,以便实体框架可以在运行时使用实际实现此关系的属性重写它们。
就像现在的情况一样,从您的("多"端(模型中,您无法访问在数据库中创建的外键。您确实可以访问它引用的记录,但不能访问外键本身(至少不能在不获取其他记录的情况下(。若要解决此问题,可以告诉实体框架使用显式声明的属性作为外键,如下所示:
[ForeignKey("Quiz")]
public int QuizId { get; set; }
ForeignKey
属性表示以下int
属性(QuizId
(将是属性Quiz
使用的实际外键,而不是让它在表中隐式创建自己的外键,这是我们无法访问的。
换句话说:无论如何都要创建一个外键,因为你引用了另一个模型。该属性用于表示您希望自己访问该外键。在大多数情况下,你会想要这个。
使用实体框架,您可以预先加载子实体:
return dba.Quiz.Include("Questions").Include("Questions.Answers").ToList();
或者使用 lambda 语法(如果您再次重命名属性,则不会中断(:
return dba.Quiz.Include(q => q.Questions.Select(x => x.Answers)).ToList();
请参阅有关 Include 方法的备注以了解其语法。
此外,您应该将密钥固定在实体Answer
。它应该是asId
,因为您将Id
用作问题的外键(顺便说一句,奇怪的命名(:
public class Answers
{
[Key]
public int asId { get; set; } // use this property as PK
public int Id { get; set; } // because this is FK
public string Text { get; set; }
}
使用 Include 方法预先加载相关实体,如下所述:http://msdn.microsoft.com/en-US/data/jj574232