豚吐露@wiki

SELECTした結果をINSERTしたい

最終更新:

ohden

- view
管理者のみ編集可

SELECTした結果をINSERTしたい


Windows11 21H2(22000.2836)
Visual Studio Professional2019 Version 16.11.33
Microsoft.EntityFrameworkCore.SqlServer 5.0.17
Microsoft SQL Server 2019 Express Edition 15.0.2104.1 (x64)

前提
以下のような構造のUserAとUserBってtableがある。table構造はUserA、Bで全く同じ。
  1. CREATE TABLE UserA(
  2. ID INT PRIMARY KEY,
  3. NAME VARCHAR(64) UNIQUE NOT NULL,
  4. PASSWORD VARBINARY(MAX) NULL,
  5. DETAIL VARCHAR(MAX) NULL
  6. );
  7.  
  8. CREATE TABLE UserB(
  9. ID INT PRIMARY KEY,
  10. NAME VARCHAR(64) UNIQUE NOT NULL,
  11. PASSWORD VARBINARY(MAX) NULL,
  12. DETAIL VARCHAR(MAX) NULL
  13. );
  14.  
  15. INSERT INTO UserA VALUES (1, 'hoge', NULL, 'hoge memo')
  16. INSERT INTO UserA VALUES (2, 'fuga', NULL, 'fuga memo')
  17. INSERT INTO UserA VALUES (3, 'piyo', NULL, 'piyo memo')
  18. INSERT INTO UserA VALUES (4, 'hage', NULL, 'hage memo')

UserAにだけ、以下のようなdataが入ってて、UserBの中身は空。

INSERT INTO Table SELECT...
空のUserBに対して、以下のようなSQLを実行すると...
  1. INSERT INTO UserB SELECT * FROM UserA;

UserAの内容がまるっとUserBに入る。

INSERT INTO Table SELECT...をEFでやってみる
これをEFを用いてやってみる。
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel.DataAnnotations;
  4. using Microsoft.EntityFrameworkCore;
  5. using Microsoft.Extensions.Configuration;
  6.  
  7. namespace Hoge.Models.dto
  8. {
  9. [Table("UserA")]
  10. public class UserA
  11. {
  12. [Key]
  13. public int ID { get; set; }
  14. public string NAME { get; set; }
  15. public byte[]? PASSWORD { get; set; }
  16. public string? DETAIL { get; set; }
  17. }
  18.  
  19. [Table("UserB")]
  20. public class UserB
  21. {
  22. [Key]
  23. public int ID { get; set; }
  24. public string NAME { get; set; }
  25. public byte[]? PASSWORD { get; set; }
  26. public string? DETAIL { get; set; }
  27. }
  28. }
  29.  
  30. namespace Hoge.Models
  31. {
  32. public class HogeContext : DbContext
  33. {
  34. public DbSet<UserA> UserA { get; set; }
  35. public DbSet<UserB> UserB { get; set; }
  36.  
  37. public HogeContext() : base()
  38. {
  39. }
  40.  
  41. protected override void OnConfiguuring(DbContextOptionsBuilder optionsBuilder)
  42. {
  43. optionsBuilder.UseSqlServer(GetConnectionString())
  44. .EnableDetailedErrors(true)
  45. .EnableSensitiveDataLogging(true);
  46. }
  47.  
  48. protected override void OnModelCreating(ModelBuilder modelBuilder)
  49. {
  50. modelBuilder.Entity<UserA>().ToTable("UserA");
  51. modelBuilder.Entity<UserB>().ToTable("UserB");
  52. }
  53.  
  54. protected string GetConnectionString()
  55. {
  56. var _connectionString = "Data Source=localhost\\instance; Database=HogeDB; Persist Security Info=True; User ID=hoge_user; Password=hoge_password; Connection Timeout=30;";
  57. string? connectionString = NULL; //apsettings.jsonから取得して結果格納
  58.  
  59. return connectionString ?? _connectionString;
  60. }
  61. }
  62.  
  63. public class Hoge
  64. {
  65. public void Mirroring()
  66. {
  67. try
  68. {
  69. using(var db = new HogeContext())
  70. {
  71. //var res_a = db.UserA.Any();
  72. //var res_b = db.UserB.Any();
  73. //var list_a = db.UserA.ToList();
  74. //var list_b = db.UserB.ToList();
  75.  
  76. var query = db.UserA
  77. .Where(a => !db.UserB.Any(b => b.ID == a.ID))
  78. .Select(a => new UserB()
  79. {
  80. ID = a.ID,
  81. NAME = a.NAME,
  82. PASSWORD = a.PASSWORD,
  83. DETAIL = a.DETAIL
  84. });
  85.  
  86. db.UserB.AddRange(query);
  87. db.SaveChanges();
  88. }
  89. }
  90. catch(Exception e)
  91. {
  92. Console.WriteLine(e.Message);
  93. }
  94. }
  95. }
  96. }

NGな構成がある
上記のようにすれば大体のdata構造で上手く行く。
が、失敗するpatternもあった。
解決策としては、AddRangeに渡す時に、ToList()してやること。

この部分を...
db.UserB.AddRange(query);
こうやってやるだけ。
db.UserB.AddRange(query.ToList());

当然ToListするタイミングでselectが発行されちゃうので、'INSERT INTO SELECT...'なSQLとはならない。

原因は分かって無い。
が、状況として失敗するところでは、GroupJoinを使用していた。
機会があれば、もう少し裏取りしてまとめたいところ。


更新日: 2024年04月08日 (月) 09時54分50秒

名前:
コメント:

すべてのコメントを見る
添付ファイル
記事メニュー
目安箱バナー