豚吐露@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)
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で全く同じ。
- CREATE TABLE UserA(
- ID INT PRIMARY KEY,
- NAME VARCHAR(64) UNIQUE NOT NULL,
- PASSWORD VARBINARY(MAX) NULL,
- DETAIL VARCHAR(MAX) NULL
- );
-
- CREATE TABLE UserB(
- ID INT PRIMARY KEY,
- NAME VARCHAR(64) UNIQUE NOT NULL,
- PASSWORD VARBINARY(MAX) NULL,
- DETAIL VARCHAR(MAX) NULL
- );
-
- INSERT INTO UserA VALUES (1, 'hoge', NULL, 'hoge memo')
- INSERT INTO UserA VALUES (2, 'fuga', NULL, 'fuga memo')
- INSERT INTO UserA VALUES (3, 'piyo', NULL, 'piyo memo')
- INSERT INTO UserA VALUES (4, 'hage', NULL, 'hage memo')
UserAにだけ、以下のようなdataが入ってて、UserBの中身は空。


INSERT INTO Table SELECT...
空のUserBに対して、以下のようなSQLを実行すると...
- INSERT INTO UserB SELECT * FROM UserA;
UserAの内容がまるっとUserBに入る。

→ 


INSERT INTO Table SELECT...をEFでやってみる
これをEFを用いてやってみる。
- using System;
- using System.Collections.Generic;
- using System.ComponentModel.DataAnnotations;
- using Microsoft.EntityFrameworkCore;
- using Microsoft.Extensions.Configuration;
-
- namespace Hoge.Models.dto
- {
- [Table("UserA")]
- public class UserA
- {
- [Key]
- public int ID { get; set; }
- public string NAME { get; set; }
- public byte[]? PASSWORD { get; set; }
- public string? DETAIL { get; set; }
- }
-
- [Table("UserB")]
- public class UserB
- {
- [Key]
- public int ID { get; set; }
- public string NAME { get; set; }
- public byte[]? PASSWORD { get; set; }
- public string? DETAIL { get; set; }
- }
- }
-
- namespace Hoge.Models
- {
- public class HogeContext : DbContext
- {
- public DbSet<UserA> UserA { get; set; }
- public DbSet<UserB> UserB { get; set; }
-
- public HogeContext() : base()
- {
- }
-
- protected override void OnConfiguuring(DbContextOptionsBuilder optionsBuilder)
- {
- optionsBuilder.UseSqlServer(GetConnectionString())
- .EnableDetailedErrors(true)
- .EnableSensitiveDataLogging(true);
- }
-
- protected override void OnModelCreating(ModelBuilder modelBuilder)
- {
- modelBuilder.Entity<UserA>().ToTable("UserA");
- modelBuilder.Entity<UserB>().ToTable("UserB");
- }
-
- protected string GetConnectionString()
- {
- var _connectionString = "Data Source=localhost\\instance; Database=HogeDB; Persist Security Info=True; User ID=hoge_user; Password=hoge_password; Connection Timeout=30;";
- string? connectionString = NULL; //apsettings.jsonから取得して結果格納
-
- return connectionString ?? _connectionString;
- }
- }
-
- public class Hoge
- {
- public void Mirroring()
- {
- try
- {
- using(var db = new HogeContext())
- {
- //var res_a = db.UserA.Any();
- //var res_b = db.UserB.Any();
- //var list_a = db.UserA.ToList();
- //var list_b = db.UserB.ToList();
-
- var query = db.UserA
- .Where(a => !db.UserB.Any(b => b.ID == a.ID))
- .Select(a => new UserB()
- {
- ID = a.ID,
- NAME = a.NAME,
- PASSWORD = a.PASSWORD,
- DETAIL = a.DETAIL
- });
-
- db.UserB.AddRange(query);
- db.SaveChanges();
- }
- }
- catch(Exception e)
- {
- Console.WriteLine(e.Message);
- }
- }
- }
- }
NGな構成がある
上記のようにすれば大体のdata構造で上手く行く。
が、失敗するpatternもあった。
解決策としては、AddRangeに渡す時に、ToList()してやること。
が、失敗するpatternもあった。
解決策としては、AddRangeに渡す時に、ToList()してやること。
この部分を...
db.UserB.AddRange(query);
こうやってやるだけ。
db.UserB.AddRange(query.ToList());
当然ToListするタイミングでselectが発行されちゃうので、'INSERT INTO SELECT...'なSQLとはならない。
原因は分かって無い。
が、状況として失敗するところでは、GroupJoinを使用していた。
機会があれば、もう少し裏取りしてまとめたいところ。
が、状況として失敗するところでは、GroupJoinを使用していた。
機会があれば、もう少し裏取りしてまとめたいところ。
更新日: 2024年04月08日 (月) 09時54分50秒