我有一個由EF Core Code First DB支持的基本ASP.NET Core應用程序。簡單地說,我剛剛添加了一些新的功能來操作附加到某個父對象的數據對象的集合,這看起來沒有任何可解釋的原因。
父對象:
public class Character
{
public Guid Id { get; set; }
// int/string properties omitted
public ICollection<CharacterMerit> CharacterMerits { get; set; }
}
有問題的對象:
public class CharacterMerit
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public Guid CharacterId { get; set; }
public MeritKey MeritKey { get; set; } // enum
}
此列表在兩個位置更新 - 角色創建和專用於這些“優點”的單獨操作。單獨的操作只是將這些CharacterMerit
對象的列表作為JSON接收,確保字符對象存在並將它們拋出到存儲庫層。這裡沒問題。
啟動:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
options.Password.RequireNonAlphanumeric = false;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddMvc();
// Add application services.
services.AddScoped<ISheetsRepository, SheetsRepository>();
services.AddTransient<IViewModelFactory, ViewModelFactory>();
services.AddTransient<SeedAdminRole>();
}
庫:
public bool UpdateMerits(Guid characterId, List<CharacterMerit> merits)
{
var dbCharacter = _dbcontext.Characters.Include(c => c.CharacterMerits).First(c => c.Id == characterId);
if (dbCharacter.CharacterMerits.Any())
{
_dbcontext.CharacterMerits.RemoveRange(dbCharacter.CharacterMerits);
dbCharacter.CharacterMerits = null;
_dbcontext.SaveChanges();
}
dbCharacter.CharacterMerits = merits;
_dbcontext.SaveChanges();
return true;
}
public bool AddOrUpdateCharacter(Character character, bool date = true)
{
if (date)
{
character.LastUpdated = DateTime.Now;
}
if (_dbcontext.Characters.FirstOrDefault(c => c.Id == character.Id) == null)
{
_dbcontext.Characters.Add(character);
}
else
{
_dbcontext.Characters.Update(character);
}
_dbcontext.SaveChanges();
return true;
}
問題出在角色創造上。創建動作:
[HttpPost]
public async Task<IActionResult> Create(BasicInfoViewModel viewModel)
{
var character = new Character
{
// property initialisation omitted for brevity
// Id property is not initialised here, EF does this
};
if(viewModel.Species != "Other")
{
character.CharacterMerits = new List<CharacterMerit>();
character.CharacterMerits.Add(new CharacterMerit
{
MeritKey = MeritKey.Default; // for sake of example
});
}
_repository.AddOrUpdateCharacter(character); // just adds the Character object to collection in dbcontext and calls SaveChanges()
// redirect to another action
}
每當我嘗試執行此操作時,我都會收到以下錯誤(有趣的是,它沒有被調試器捕獲,只是直接進入瀏覽器,包含在DbUpdateException
)。它似乎在SaveChanges()
調用上失敗了。
System.Data.SqlClient.SqlException: A transport-level error has occurred when receiving results from the server. (provider: Session Provider, error: 19 - Physical connection is not usable)
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj, UInt32 error)
at System.Data.SqlClient.TdsParserStateObject.ReadSniSyncOverAsync()
at System.Data.SqlClient.TdsParserStateObject.TryReadNetworkPacket()
at System.Data.SqlClient.TdsParserStateObject.TryPrepareBuffer()
at System.Data.SqlClient.TdsParserStateObject.TryReadByte(Byte& value)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
at System.Data.SqlClient.SqlDataReader.get_MetaData()
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds)
at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior)
at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.Execute(IRelationalConnection connection, String executeMethod, IReadOnlyDictionary`2 parameterValues, Boolean closeConnection)
at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteReader(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection connection)
ClientConnectionId:998c6223-efc9-4172-a344-4b2ba71cf4c9
Error Number:-1,State:0,Class:20
如果我刪除添加到CharacterMerits
列表中的代碼,一切都會順利進行。我試過了什麼?
Character
對象之外,還有上述內容。 Character
對象)並使用上面的UpdateMerits()方法Startup
我已經考慮過將此操作重定向到另一個可以執行此操作的操作,但是從概念的角度來看,此代碼屬於此操作,如果存在,則無法解決根本問題。應用程序當前正在localdb上運行,但是在標準SQL Server數據庫上也運行了部署版本。這不是我第一次使用EF中的集合,所以我完全不知道這裡可能出現什麼問題。