我試圖在兩個物體之間創建關系,發現當資料庫中的外鍵為空時,EF Core 會拋出 SqlNullValueException: Data is Null例外。
這是主要物體(Person表):
[Key]
public int PersonId { get; set; }
public int? StaffId { get; set; }
public virtual StaffView? StaffView { get; set; }
這是相關的物體(Staff表):
[Key]
public int StaffId { get; set; }
public int? PersonId { get; set; }
public virtual PersonView? PersonView { get; set; }
這是我的DbContext課:
public virtual DbSet<PersonView>? PersonViews { get; set; } = null!;
public virtual DbSet<StaffView> StaffViews { get; set; } = null!;
modelBuilder.Entity<PersonView>(entity =>
{
entity.ToTable("Persons", "Person");
entity.Property(e => e.PersonId).HasColumnName("Person_ID").ValueGeneratedOnAdd();
entity.HasKey(e => e.PersonId);
entity.Property(e => e.StaffId).HasColumnName("Staff_ID");
entity.HasOne(a => a.StaffView)
.WithOne(b => b.PersonView)
.HasPrincipalKey<PersonView>(b => b.StaffId)
.HasForeignKey<StaffView>(b => b.StaffId)
.IsRequired(false);
});
modelBuilder.Entity<StaffView>(entity =>
{
entity.ToTable("Staff", "Person");
entity.Property(e => e.StaffId).HasColumnName("Staff_ID").ValueGeneratedOnAdd();
entity.HasKey(e => e.StaffId);
entity.Property(e => e.PersonId).HasColumnName("Person_ID");
entity.HasOne(a => a.PersonView)
.WithOne(b => b.StaffView)
.HasPrincipalKey<PersonView>(b => b.StaffId)
.HasForeignKey<StaffView>(b => b.StaffId)
.IsRequired(false);
});
EDM 條目(在 中Program.cs):
builder.EntitySet<PersonView>("OViewPersons");
控制器:
public class OViewPersonsController : ODataController
{
private readonly ViewContext? _context;
public OViewPersonsController(ViewContext context)
{
_context = context;
}
[HttpGet]
[EnableQuery(MaxExpansionDepth = 6)]
public ActionResult<IQueryable<PersonView>> Get()
{
try
{
IQueryable<PersonView> queryResults = _context.PersonViews
.Include(sta => sta.StaffView);
return Ok(queryResults);
}
catch (Exception e)
{
return StatusCode(StatusCodes.Status500InternalServerError, e.Message);
}
}
}
資料庫架構:
[Person].[Persons]
[Person_ID] [int] IDENTITY(1,1) NOT NULL
[Staff_ID] [int] NULL
[Person].[Staff]
[Staff_ID] [int] IDENTITY(1,1) NOT NULL
[Person_ID] [int] NULL
當表Staff ID中的Persons為 Null 時:
Person_Id Staff_Id
--------------------
397748 NULL
拋出以下例外:
Microsoft.EntityFrameworkCore.Query:錯誤:迭代背景關系型別“GatewayApi.DbContexts.GatewayApiContext”的查詢結果時發生例外。System.Data.SqlTypes.SqlNullValueException:資料為空。不能對 Null 值呼叫此方法或屬性。
在 Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()
的
Microsoft.Data.SqlClient.SqlBuffer.get_Int32()
使用的軟體及其版本:
- VS 2022 - 版本 17.3.6
- Microsoft.EntityFrameworkCore {6.0.10} GatewayApi
- Microsoft.EntityFrameworkCore.SqlServer {6.0.10} GatewayApi
- Swashbuckle.AspNetCore {6.4.0} GatewayApi
- Microsoft.AspNetCore.Mvc.NewtonsoftJson {6.0.10} GatewayApi
- System.Configuration.ConfigurationManager {6.0.1} GatewayApi
- Microsoft.EntityFrameworkCore.Tools {6.0.10} GatewayApi
- Twilio {5.81.0} GatewayApi
- Microsoft.VisualStudio.Web.CodeGeneration.Design {6.0.10} GatewayApi
- Microsoft.AspNetCore.OData {8.0.11} GatewayApi
我需要一個不會出錯并允許在外鍵欄位中使用空值的結果集。
我嘗試了許多解決方案,但似乎沒有任何效果
我在模型類中添加了“外鍵”注釋:
[ForeignKey("StaffView")]
public int? StaffId { get; set; }
和
[ForeignKey("StaffId")]
public virtual StaffView? StaffView { get; set; }
我嘗試了使用和不.IsRequired(false)使用DbContext.
我嘗試了將所有不同引數標識為空或非空的各種組合
public int? StaffId { get; set; }
和
public int StaffId { get; set; }
我嘗試在 Project Build 配置中禁用 Nullable。
我嘗試將Staff_ID表中的Person從可為空更改為不可為空。
我已經在網上搜索并嘗試了許多其他建議,但無法全部記住。
我進行了廣泛的搜索,并相信它與主要物體中的 Int32 外鍵為空有關。我找到了很多與將引數注釋或標記為 null 相關的答案,但未能成功找到與外鍵資料庫欄位中的 null 相關的解決方案。
我試圖盡可能詳細,但如果我遺漏了什么,請告訴我。
幾天來我一直在嘗試解決這個問題,但我似乎無法讓它按預期作業。非常感謝任何和所有幫助。
提前非常感謝!
uj5u.com熱心網友回復:
如果我們從現實世界物件層次結構的角度來考慮,一個Staff成員是一個 Person,但不是所有的人都是Staff成員,所以1 Person 物體到 0 或 1 個 Staff是有意義的。但在 EF 中,這種關系的倒數
實際上是1 Staff : many Persons。如果您需要故意將許多 Persons限制為 1,那么通過在Staff表上實作唯一約束更容易實作。
- 這不是實作這種關系的唯一方法,但在 EF 中,無論是在配置方面還是在長期管理方面都容易得多。
對于這個簡單的設定,我們甚至不需要使用流暢的配置,我們可以使用屬性表示法:
[Table("Persons", Schema = "Person")]
public class PersonView
{
[Key]
public int PersonId { get; set; }
public virtual ICollection<StaffView> StaffViews { get; set; }
= new HashSet<StaffView>();
}
[Table("Staff", Schema = "Person")]
public class StaffView
{
[Key]
public int StaffId { get; set; }
public int? PersonId { get; set; }
[ForeignKey("PersonId")]
public virtual PersonView? PersonView { get; set; }
}
這仍然使您可以Staff從Person. 這種型別的關系明確定義Person為委托人和“員工”為受撫養人。
如果您的關系需要為 1:0-1,則 EF 通過繼承處理此問題,將 重新PersonId用作StaffView. 為此,您正在有效地實作Table-Per-Type (TPT) 層次結構,這在 EF Core 中實作是有問題的。這是可以做到的,我從 EF6 升級的專案仍然可以在 TPT 上運行良好,但在大多數情況下,它會引入一定程度的技術債務,而你可以做到這一點。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/524143.html
