🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

Q&A

解決済

1回答

1622閲覧

C# ASP.NET チュートリアルにて decimal→string変換がうまくいかない

yayaya22

総合スコア51

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

0グッド

0クリップ

投稿2022/08/28 10:17

編集2022/08/29 00:58

パート 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; } } }

イメージ追記:
イメージ説明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2022/08/28 11:15 編集

ASP.NET のタグをつけてください。MVC なら Razor のタグは外してください。 で、質問は何ですか? 書いてないけど・・・ 
yayaya22

2022/08/28 13:13

decimalからstring変換がうまくいかないようで、結果がリストとして返らずreturn文にエラーが出ているようです こちらのエラーを解決し、SeedDataの内容を反映させたいですね
退会済みユーザー

退会済みユーザー

2022/08/28 14:07 編集

> decimalからstring変換がうまくいかないようで エラーメッセージはその逆の Unable to cast object of type 'System.String' to type 'System.Decimal'. となってますけど? なんにせよ、チュートリアル通りにやったのならそういうエラーが出るのは考えにくいのですが、何かチュートリアルと違ったことをしてませんか? その前のパートまではチュートリアルと少しも違えることなく 100% チュートリアル通りに実装して一切問題なくできているのですか? > SeedDataの内容を反映させたいですね 直接 DB を見てシードされてないのは確認したのですか?
yayaya22

2022/08/28 15:14

sql serverオブジェクトエクスプロ―ラーで、デザイン表示でDBを確認すると、 Price のデータ型がnvarchar(MAX)になっていました。 decimal(18,0)に直したところ、sqlエラーになり、直せない状態になってしまいました。 sql構文をいじるのは、まだ未経験なのでやり直したほうがよろしいでしょうか。
退会済みユーザー

退会済みユーザー

2022/08/28 22:37

質問に答えてください。以下に再掲します。 チュートリアル通りにやったのならそういうエラーが出るのは考えにくいのですが、何かチュートリアルと違ったことをしてませんか?  その前のパートまではチュートリアルと少しも違えることなく 100% チュートリアル通りに実装して一切問題なくできているのですか?
退会済みユーザー

退会済みユーザー

2022/08/28 23:08

> Price のデータ型がnvarchar(MAX)になっていました。 そうなっていると言うことは、Migration (EF Code First で DB を生成) した際 Model の当該プロパティの型が string (または string?) になっていたということだと思います。 質問のコードを見ると decimal? となってますが、 Migration の後いじりまくって色々変えたのでは?
yayaya22

2022/08/28 23:31 編集

はい、いじりまくったと思います。
退会済みユーザー

退会済みユーザー

2022/08/29 00:13

何をどういじったのかを書いてほしいのですが、今となっては分からないということですか? 質問に貼ったコードはいじったあとの現状ですか? > sql serverオブジェクトエクスプロ―ラーで、デザイン表示でDBを確認すると、 そのスクリーンショットを撮って質問欄に貼ってください。
yayaya22

2022/08/29 01:01

>何をどういじったのかを書いてほしいのですが、今となっては分からないということですか? 始めに Price = 7.99M にしていてエラーがでたので、(確か同じエラーdecimal) Price = "7.99M" のように文字列にして、migrateしたのかもしれません。 貼り付けました
退会済みユーザー

退会済みユーザー

2022/08/29 01:13 編集

質問に答えよう。話が通じなくなる 何をどういじったのかを書いてほしいのですが、今となっては分からないということですか? 質問に貼ったコードはいじったあとの現状ですか?
yayaya22

2022/08/29 01:38

>何をどういじったのかを書いてほしいのですが、今となっては分からないということですか? はい、不明です >質問に貼ったコードはいじったあとの現状ですか? いじったあとになります。
退会済みユーザー

退会済みユーザー

2022/08/29 01:57

>> 何をどういじったのかを書いてほしいのですが、今となっては分からないということですか? > はい、不明です そういうことですと、チュートリアルの最初から、チュートリアルと完全に同じコードでゼロから作り直してもらう方がはやそうです。 ・・・が、その前にやってみてもよさそうなことを後で回答欄に書いておきます。今 PC を使える環境にないので、しばしお待ちください。
yayaya22

2022/08/29 05:22

再度 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.
退会済みユーザー

退会済みユーザー

2022/08/29 23:54 編集

Price が nvarchar(max) に設定されていて、その後シードする際、 > 始めに Price = 7.99M にしていてエラーがでたので、(確か同じエラーdecimal)Price = "7.99M" のように文字列にして ・・・としたので、今回の Migration 操作前に DB の Price 列は "7.99M" というような文字列でシードされていたのでは? エラーメッセージを見ると、今回の Migration 操作で、シード済みの NULL 可の nvarchar(max) のデータを、NULL 不可の decimal 型に変えようとして失敗しているように見えます。 もし、原因を追及したいのなら、結果の DB がどうなっているか調べて、対処方法を考えてみてはいかがですか? ゼロからやり直した方が解決は早そうな気はしますので、原因追及に興味がないのであればお勧めはしませんが。
guest

回答1

0

ベストアンサー

上の質問欄の下の 2022/08/29 10:57 の私のコメントで「後で回答欄に書いておきます」と書いた件です。

何をどういじったのかを書いてほしいのですが、今となっては分からないということですか?

はい、不明です

そういうことですと、チュートリアルの最初から、チュートリアルと完全に同じコードでゼロから作り直してもらう方が早そうです・・・が、その前にやってみてもよさそうなことを書いておきます。

sql serverオブジェクトエクスプロ―ラーで、デザイン表示でDBを確認すると、Price のデータ型がnvarchar(MAX)になっていました。

そうなっていると言うことは、最初、チュートリアルのステップ 3 で Movie クラスを作ったときに Price プロパティの型が decimal ではなくて string (または string?) になっていて、「最初の移行」で Migration (EF Code First で DB を生成) した際 DB の Price フィールドの型がそれに合わせて nvarchar(MAX) になったということだと思います。

であれば、再度 Migration 操作をして DB の Price フィールドの型を decimal に変更すれば問題は解決するかもしれません。

ただし、その後も Migration 操作をしたとか、いじり倒して訳のわからない状況になっているなら無駄かもしれません。その場合は、質問者さんが何をしたかわからない赤の他人がアドバイスできることはなさそうです。ゼロから作り直してください。

まず、チュートリアルのステップ 3 「最初の移行」のセクションに「Migrations/{timestamp}_InitialCreate.cs 移行ファイルが生成されます」と書いてありますが、それを見てください。

チュートリアルの通りの Movie クラスの定義なら以下のようになっているはず。質問者さんの場合は赤線で示したコードが Column<string> ... nvarchar(max) になってませんか?

イメージ説明

そうでであれば、今の Movie クラスの定義のまま(Price プロパティの方は decimal)、Migration 操作(Add-Migration Modified)をしてみてください。

成功すれば Migrations フォルダに {timestamp}_Modified.cs ファイルが生成されるはずなので、その中身をチェックしてから Update-Database コマンドをかけてください。

それで DB が以下のようになっていれば不整合はなくなるはずです。

イメージ説明

投稿2022/08/29 04:04

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問