Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
EF CoreのOwned typesのサンプル
use Test;
begin tran;
-- テーブル作成
drop table if exists dbo.Character;
create table dbo.Character(
Id int,
Name nvarchar(4) not null,
Level int not null,
Hp int not null,
Mp int not null,
constraint PK_Character primary key(Id)
);
/*
-- データ投入
insert into dbo.Character(
Id, Name, Level, Hp, Mp
)
output inserted.*
values
(1, N'エイト', 10, 59, 32),
(2, N'ゼシカ', 10, 47, 28);
*/
commit;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
namespace ConsoleApp {
// ステータス
public class Status {
// HP
public int Hp { get; set; }
// MP
public int Mp { get; set; }
}
/*
public class Status {
// 最大HP
public int MaxHp { get; set; }
// 最大MP
public int MaxMp { get; set; }
// ちから
public int Strength { get; set; }
// すばやさ
public int Speed { get; set; }
// みのまもり
public int Guard { get; set; }
// かしこさ
public int Wisdom { get; set; }
// 攻撃力
public int Attack { get; set; }
// 守備力
public int Defense { get; set; }
}
*/
// キャラクター
public class Character {
public int Id { get; set; }
public string Name { get; set; }
public int Level { get; set; }
public Status Status { get; set; }
}
// ロガープロバイダー
public class AppLoggerProvider : ILoggerProvider {
public ILogger CreateLogger(string categoryName) {
if (string.Equals(categoryName, DbLoggerCategory.Database.Command.Name)) {
return new ConsoleLogger();
}
return NullLogger.Instance;
}
public void Dispose() {
}
// ロガー
private class ConsoleLogger : ILogger {
public IDisposable BeginScope<TState>(TState state) => null;
// 情報レベル以上のログを有効にする
public bool IsEnabled(LogLevel logLevel) => logLevel >= LogLevel.Information;
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception,
Func<TState, Exception, string> formatter) {
Console.WriteLine(formatter(state, exception));
Console.WriteLine("---");
}
}
}
// DBコンテキスト
public class AppDbContext : DbContext {
public AppDbContext(bool tracking = false) {
ChangeTracker.QueryTrackingBehavior = tracking
? QueryTrackingBehavior.TrackAll
: QueryTrackingBehavior.NoTracking;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
var connectionString = new SqlConnectionStringBuilder {
DataSource = ".",
InitialCatalog = "Test",
IntegratedSecurity = true,
}.ToString();
optionsBuilder.UseSqlServer(connectionString);
}
protected override void OnModelCreating(ModelBuilder modelBuilder) {
// Characterテーブルへのマッピング
modelBuilder.Entity<Character>().ToTable(nameof(Character));
// CharacterがStatusを所有する
modelBuilder.Entity<Character>().OwnsOne(
character => character.Status,
statusBuilder => {
// Statusをカラムへマッピング
// デフォルトだと「Status_Hp」「「Status_Mp」」といったカラムにマッピングされる
statusBuilder.Property(status => status.Hp).HasColumnName(nameof(Status.Hp));
statusBuilder.Property(status => status.Mp).HasColumnName(nameof(Status.Mp));
});
}
}
class Program {
private static void Dump(IEnumerable<Character> characters) {
foreach (var character in characters) {
Console.WriteLine($"{character.Name}");
Console.WriteLine($"Lv {character.Level}");
Console.WriteLine($"HP {character.Status.Hp}");
Console.WriteLine($"MP {character.Status.Mp}");
Console.WriteLine();
}
}
static void Main(string[] args) {
using (var dbContext = new AppDbContext()) {
// ロガープロバイダーを設定
var serviceProvider = dbContext.GetInfrastructure();
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
loggerFactory.AddProvider(new AppLoggerProvider());
}
// データ投入
using (var dbContext = new AppDbContext(tracking: true)) {
dbContext.Set<Character>().AddRange(
new Character {
Id = 1,
Name = "エイト",
Level = 10,
Status = new Status { Hp = 59, Mp = 32 },
},
new Character {
Id = 2,
Name = "ゼシカ",
Level = 10,
Status = new Status { Hp = 47, Mp = 28 },
});
dbContext.SaveChanges();
/*
Executed DbCommand(36ms) [Parameters=[@p0='?', @p1='?', @p2='?' (Size = 4000), @p3='?', @p4='?', @p5='?', @p6='?', @p7='?' (Size = 4000), @p8='?', @p9='?'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
INSERT INTO[Character] ([Id], [Level], [Name], [Hp], [Mp])
VALUES(@p0, @p1, @p2, @p3, @p4),
(@p5, @p6, @p7, @p8, @p9);
---
*/
}
// 確認
using (var dbContext = new AppDbContext()) {
var characters = dbContext.Set<Character>().ToList();
/*
Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT [c].[Id], [c].[Level], [c].[Name], [c].[Id], [c].[Hp], [c].[Mp]
FROM [Character] AS [c]
---
*/
Dump(characters);
/*
エイト
Lv 10
HP 59
MP 32
ゼシカ
Lv 10
HP 47
MP 28
*/
}
// データ更新
using (var dbContext = new AppDbContext(tracking: true)) {
// エイトを取得
var character = dbContext.Set<Character>().Find(1);
/*
Executed DbCommand(1ms) [Parameters=[@__get_Item_0='?'], CommandType='Text', CommandTimeout='30']
SELECT TOP(1) [e].[Id], [e].[Level], [e].[Name], [e].[Id], [e].[Hp], [e].[Mp]
FROM[Character] AS[e]
WHERE[e].[Id] = @__get_Item_0
---
*/
// エイトがレベルアップ
character.Level += 1;
character.Status.Hp += 12;
character.Status.Mp += 2;
dbContext.SaveChanges();
/*
SET NOCOUNT ON;
UPDATE [Character] SET [Level] = @p0, [Hp] = @p1, [Mp] = @p2
WHERE [Id] = @p3;
SELECT @@ROWCOUNT;
---
*/
}
// 確認
using (var dbContext = new AppDbContext()) {
var characters = dbContext.Set<Character>().ToList();
/*
Executed DbCommand(0ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT[c].[Id], [c].[Level], [c].[Name], [c].[Id], [c].[Hp], [c].[Mp]
FROM[Character] AS[c]
---
*/
Dump(characters);
/*
エイト
Lv 11
HP 71
MP 34
ゼシカ
Lv 10
HP 47
MP 28
*/
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.