实体框架在三个表中提取 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("}

我收到了这条异常消息..有什么帮助吗?

谢谢!

实体框架在三个表中提取 null

我不认为你已经按照你认为的方式建立了你的关系。

请尝试以下更改

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