パート 6: ASP.NET Core のコントローラーのメソッドとビュー
decimal変換でエラーが発生しています。
エラー内容
InvalidCastException: Unable to cast object of type 'System.String' to type 'System.Decimal'. Microsoft.Data.SqlClient.SqlBuffer.get_Decimal() lambda_method35(Closure , QueryContext , DbDataReader , ResultContext , SingleQueryResultCoordinator ) Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable<T>+AsyncEnumerator.MoveNextAsync() Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync<TSource>(IQueryable<TSource> source, CancellationToken cancellationToken) Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync<TSource>(IQueryable<TSource> source, CancellationToken cancellationToken) MvcMovie.Controllers.MoviesController.Index() in MoviesController.cs + return _context.Movie != null ? Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor+TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, object controller, object[] arguments) System.Threading.Tasks.ValueTask<TResult>.get_Result() System.Runtime.CompilerServices.ValueTaskAwaiter<TResult>.GetResult() Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask<IActionResult> actionResultValueTask) Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted) Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context) Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted) Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.
MovieController.cs
C#
1using System; 2using System.Collections.Generic; 3using System.Linq; 4using System.Threading.Tasks; 5using Microsoft.AspNetCore.Mvc; 6using Microsoft.AspNetCore.Mvc.Rendering; 7using Microsoft.EntityFrameworkCore; 8using MvcMovie.Data; 9using MvcMovie.Models; 10 11namespace MvcMovie.Controllers 12{ 13 public class MoviesController : Controller 14 { 15 private readonly MvcMovieContext _context; 16 17 public MoviesController(MvcMovieContext context) 18 { 19 _context = context; 20 } 21 22 // GET: Movies 23 public async Task<IActionResult> Index() 24 { 25 return _context.Movie != null ? 26 View(await _context.Movie.ToListAsync()) : 27 Problem("Entity set 'MvcMovieContext.Movie' is null."); 28 } 29 30 // GET: Movies/Details/5 31 public async Task<IActionResult> Details(int? id) 32 { 33 if (id == null || _context.Movie == null) 34 { 35 return NotFound(); 36 } 37 38 var movie = await _context.Movie 39 .FirstOrDefaultAsync(m => m.Id == id); 40 if (movie == null) 41 { 42 return NotFound(); 43 } 44 45 return View(movie); 46 } 47 48 // GET: Movies/Create 49 public IActionResult Create() 50 { 51 return View(); 52 } 53 54 // POST: Movies/Create 55 // To protect from overposting attacks, enable the specific properties you want to bind to. 56 // For more details, see http://go.microsoft.com/fwlink/?LinkId=317598. 57 [HttpPost] 58 [ValidateAntiForgeryToken] 59 public async Task<IActionResult> Create([Bind("Id,Title,ReleaseDate,Genre,Price")] Movie movie) 60 { 61 if (ModelState.IsValid) 62 { 63 _context.Add(movie); 64 await _context.SaveChangesAsync(); 65 return RedirectToAction(nameof(Index)); 66 } 67 return View(movie); 68 } 69 70 // GET: Movies/Edit/5 71 public async Task<IActionResult> Edit(int? id) 72 { 73 if (id == null || _context.Movie == null) 74 { 75 return NotFound(); 76 } 77 78 var movie = await _context.Movie.FindAsync(id); 79 if (movie == null) 80 { 81 return NotFound(); 82 } 83 return View(movie); 84 } 85 86 // POST: Movies/Edit/5 87 // To protect from overposting attacks, enable the specific properties you want to bind to. 88 // For more details, see http://go.microsoft.com/fwlink/?LinkId=317598. 89 [HttpPost] 90 [ValidateAntiForgeryToken] 91 public async Task<IActionResult> Edit(int id, [Bind("Id,Title,ReleaseDate,Genre,Price")] Movie movie) 92 { 93 if (id != movie.Id) 94 { 95 return NotFound(); 96 } 97 98 if (ModelState.IsValid) 99 { 100 try 101 { 102 _context.Update(movie); 103 await _context.SaveChangesAsync(); 104 } 105 catch (DbUpdateConcurrencyException) 106 { 107 if (!MovieExists(movie.Id)) 108 { 109 return NotFound(); 110 } 111 else 112 { 113 throw; 114 } 115 } 116 return RedirectToAction(nameof(Index)); 117 } 118 return View(movie); 119 } 120 121 // GET: Movies/Delete/5 122 public async Task<IActionResult> Delete(int? id) 123 { 124 if (id == null || _context.Movie == null) 125 { 126 return NotFound(); 127 } 128 129 var movie = await _context.Movie 130 .FirstOrDefaultAsync(m => m.Id == id); 131 if (movie == null) 132 { 133 return NotFound(); 134 } 135 136 return View(movie); 137 } 138 139 // POST: Movies/Delete/5 140 [HttpPost, ActionName("Delete")] 141 [ValidateAntiForgeryToken] 142 public async Task<IActionResult> DeleteConfirmed(int id) 143 { 144 if (_context.Movie == null) 145 { 146 return Problem("Entity set 'MvcMovieContext.Movie' is null."); 147 } 148 var movie = await _context.Movie.FindAsync(id); 149 if (movie != null) 150 { 151 _context.Movie.Remove(movie); 152 } 153 154 await _context.SaveChangesAsync(); 155 return RedirectToAction(nameof(Index)); 156 } 157 158 private bool MovieExists(int id) 159 { 160 return (_context.Movie?.Any(e => e.Id == id)).GetValueOrDefault(); 161 } 162 } 163} 164
SeedData.cs
C#
1using Microsoft.EntityFrameworkCore; 2using Microsoft.Extensions.DependencyInjection; 3using MvcMovie.Data; 4using System; 5using System.Linq; 6 7namespace MvcMovie.Models 8{ 9 public static class SeedData 10 { 11 public static void Initialize(IServiceProvider serviceProvider) 12 { 13 using (var context = new MvcMovieContext( 14 serviceProvider.GetRequiredService< 15 DbContextOptions<MvcMovieContext>>())) 16 { 17 // Look for any movies. 18 if (context.Movie.Any()) 19 { 20 return; // DB has been seeded 21 } 22 23 context.Movie.AddRange( 24 new Movie 25 { 26 Title = "When Harry Met Sally", 27 ReleaseDate = DateTime.Parse("1989-2-12"), 28 Genre = "Romantic Comedy", 29 Price = 7.99M 30 }, 31 32 new Movie 33 { 34 Title = "Ghostbusters ", 35 ReleaseDate = DateTime.Parse("1984-3-13"), 36 Genre = "Comedy", 37 Price = 8.99M 38 }, 39 40 new Movie 41 { 42 Title = "Ghostbusters 2", 43 ReleaseDate = DateTime.Parse("1986-2-23"), 44 Genre = "Comedy", 45 Price = 9.99M 46 }, 47 48 new Movie 49 { 50 Title = "Rio Bravo", 51 ReleaseDate = DateTime.Parse("1959-4-15"), 52 Genre = "Western", 53 Price = 3.99M 54 } 55 ); 56 context.SaveChanges(); 57 } 58 } 59 } 60}
Movie.cs
using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace MvcMovie.Models { public class Movie { public int Id { get; set; } public string? Title { get; set; } [Display(Name = "Release Date")] [DataType(DataType.Date)] public DateTime ReleaseDate { get; set; } public string? Genre { get; set; } [Column(TypeName = "decimal(18, 2)")] public decimal? Price { get; set; } } }
ASP.NET のタグをつけてください。MVC なら Razor のタグは外してください。
で、質問は何ですか? 書いてないけど・・・
decimalからstring変換がうまくいかないようで、結果がリストとして返らずreturn文にエラーが出ているようです
こちらのエラーを解決し、SeedDataの内容を反映させたいですね
> decimalからstring変換がうまくいかないようで
エラーメッセージはその逆の Unable to cast object of type 'System.String' to type 'System.Decimal'. となってますけど?
なんにせよ、チュートリアル通りにやったのならそういうエラーが出るのは考えにくいのですが、何かチュートリアルと違ったことをしてませんか? その前のパートまではチュートリアルと少しも違えることなく 100% チュートリアル通りに実装して一切問題なくできているのですか?
> SeedDataの内容を反映させたいですね
直接 DB を見てシードされてないのは確認したのですか?
sql serverオブジェクトエクスプロ―ラーで、デザイン表示でDBを確認すると、
Price のデータ型がnvarchar(MAX)になっていました。
decimal(18,0)に直したところ、sqlエラーになり、直せない状態になってしまいました。
sql構文をいじるのは、まだ未経験なのでやり直したほうがよろしいでしょうか。
質問に答えてください。以下に再掲します。
チュートリアル通りにやったのならそういうエラーが出るのは考えにくいのですが、何かチュートリアルと違ったことをしてませんか?
その前のパートまではチュートリアルと少しも違えることなく 100% チュートリアル通りに実装して一切問題なくできているのですか?
> Price のデータ型がnvarchar(MAX)になっていました。
そうなっていると言うことは、Migration (EF Code First で DB を生成) した際 Model の当該プロパティの型が string (または string?) になっていたということだと思います。
質問のコードを見ると decimal? となってますが、 Migration の後いじりまくって色々変えたのでは?
はい、いじりまくったと思います。
何をどういじったのかを書いてほしいのですが、今となっては分からないということですか?
質問に貼ったコードはいじったあとの現状ですか?
> sql serverオブジェクトエクスプロ―ラーで、デザイン表示でDBを確認すると、
そのスクリーンショットを撮って質問欄に貼ってください。
>何をどういじったのかを書いてほしいのですが、今となっては分からないということですか?
始めに Price = 7.99M にしていてエラーがでたので、(確か同じエラーdecimal)
Price = "7.99M" のように文字列にして、migrateしたのかもしれません。
貼り付けました
質問に答えよう。話が通じなくなる
何をどういじったのかを書いてほしいのですが、今となっては分からないということですか?
質問に貼ったコードはいじったあとの現状ですか?
>何をどういじったのかを書いてほしいのですが、今となっては分からないということですか?
はい、不明です
>質問に貼ったコードはいじったあとの現状ですか?
いじったあとになります。
>> 何をどういじったのかを書いてほしいのですが、今となっては分からないということですか?
> はい、不明です
そういうことですと、チュートリアルの最初から、チュートリアルと完全に同じコードでゼロから作り直してもらう方がはやそうです。
・・・が、その前にやってみてもよさそうなことを後で回答欄に書いておきます。今 PC を使える環境にないので、しばしお待ちください。
再度 Migration 操作をして DB の Price フィールドの型を decimal に変更しましたが、エラーが発生しました。
長々とすみません、ヒントをいただいたので、はじめから着実に進めてみます。ありがとうございました。
PM> Add-Migration Modified
Build started...
Build succeeded.
Microsoft.EntityFrameworkCore.Infrastructure[10403]
Entity Framework Core 6.0.8 initialized 'MvcMovieContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer:6.0.8' with options: None
An operation was scaffolded that may result in the loss of data. Please review the migration for accuracy.
To undo this action, use Remove-Migration.
PM> Update-Database
Build started...
Build succeeded.
Microsoft.EntityFrameworkCore.Infrastructure[10403]
Entity Framework Core 6.0.8 initialized 'MvcMovieContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer:6.0.8' with options: None
Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (18ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT 1
Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (14ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT OBJECT_ID(N'[__EFMigrationsHistory]');
Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT 1
Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT OBJECT_ID(N'[__EFMigrationsHistory]');
Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT [MigrationId], [ProductVersion]
FROM [__EFMigrationsHistory]
ORDER BY [MigrationId];
Microsoft.EntityFrameworkCore.Migrations[20402]
Applying migration '20220829050533_Modified'.
Applying migration '20220829050533_Modified'.
fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
Failed executing DbCommand (70ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
DECLARE @var0 sysname;
SELECT @var0 = [d].[name]
FROM [sys].[default_constraints] [d]
INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id]
WHERE ([d].[parent_object_id] = OBJECT_ID(N'[Movie]') AND [c].[name] = N'Price');
IF @var0 IS NOT NULL EXEC(N'ALTER TABLE [Movie] DROP CONSTRAINT [' + @var0 + '];');
ALTER TABLE [Movie] ALTER COLUMN [Price] decimal(18,2) NOT NULL;
ALTER TABLE [Movie] ADD DEFAULT 0.0 FOR [Price];
Failed executing DbCommand (70ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
DECLARE @var0 sysname;
SELECT @var0 = [d].[name]
FROM [sys].[default_constraints] [d]
INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id]
WHERE ([d].[parent_object_id] = OBJECT_ID(N'[Movie]') AND [c].[name] = N'Price');
IF @var0 IS NOT NULL EXEC(N'ALTER TABLE [Movie] DROP CONSTRAINT [' + @var0 + '];');
ALTER TABLE [Movie] ALTER COLUMN [Price] decimal(18,2) NOT NULL;
ALTER TABLE [Movie] ADD DEFAULT 0.0 FOR [Price];
Microsoft.Data.SqlClient.SqlException (0x80131904): Error converting data type nvarchar to numeric.
The statement has been terminated.
at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at Microsoft.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean isAsync, Int32 timeout, Boolean asyncWrite)
at Microsoft.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, Boolean sendToPipe, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry, String methodName)
at Microsoft.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteNonQuery(RelationalCommandParameterObject parameterObject)
at Microsoft.EntityFrameworkCore.Migrations.MigrationCommand.ExecuteNonQuery(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)
at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteNonQuery(IEnumerable`1 migrationCommands, IRelationalConnection connection)
at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(String targetMigration)
at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.UpdateDatabase(String targetMigration, String connectionString, String contextType)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabaseImpl(String targetMigration, String connectionString, String contextType)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabase.<>c__DisplayClass0_0.<.ctor>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
ClientConnectionId:6a3b616c-986f-4ed7-8227-88d726901f70
Error Number:8114,State:5,Class:16
Error converting data type nvarchar to numeric.
The statement has been terminated.
Price が nvarchar(max) に設定されていて、その後シードする際、
> 始めに Price = 7.99M にしていてエラーがでたので、(確か同じエラーdecimal)Price = "7.99M" のように文字列にして
・・・としたので、今回の Migration 操作前に DB の Price 列は "7.99M" というような文字列でシードされていたのでは?
エラーメッセージを見ると、今回の Migration 操作で、シード済みの NULL 可の nvarchar(max) のデータを、NULL 不可の decimal 型に変えようとして失敗しているように見えます。
もし、原因を追及したいのなら、結果の DB がどうなっているか調べて、対処方法を考えてみてはいかがですか?
ゼロからやり直した方が解決は早そうな気はしますので、原因追及に興味がないのであればお勧めはしませんが。
回答1件
あなたの回答
tips
プレビュー