SlideShare ist ein Scribd-Unternehmen logo
1 von 48
Артур Дробинский
МЦЦ Томск
Entity Framework Core: tips
and tricks
About Us
MCC Tomsk
Cloud platform
for tele-medicine
Microservices
Message Broker
SOA
.Net Core
React/Redux
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
using (SqlConnection connection =
new SqlConnection(connectionString))
{
SqlCommand command = new
SqlCommand(queryString, connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
reader.Read();
Console.WriteLine("t{0}t{1}t{2}",
reader[0], reader[1], reader[2]);
}
public class Comment
{
public int Id { get; set; }
public string Text { get; set; }
public bool IsDeleted { get; set; }
public Post Post { get; set; }
}
var context = new MyContext(options);
var comment = context.Comments.First();
Console.WriteLine("t{0}t{1}", comment.Text,
comment.Id);
var context = new MyContext(options);
var comment = context.Comments
.Include(x => x.Post)
.Where(x => x.Id > 5)
.Where(x => !x.Post.IsDeleted)
.OrderBy(x => x.Text)
.First();
Console.WriteLine("t{0}t{1}",
comment.Post.Title, comment.Text);
var sql =
@"select * from #Posts p
left join #Users u on u.Id = p.OwnerId
Order by p.Id";
var data = connection.Query<Post, User,
Post>(sql, (post, user) => { post.Owner =
user; return post; });
var post = data.First();
Pitfalls
Entities
public class Post
{
public int Id { get; private set; }
public string Title { get; set; }
public Blog Blog { get; set; }
public bool IsDeleted { get; set; }
}
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
public class Blog
{
public int Id { get; private set; }
public string Name { get; set; }
public ICollection<Post> Posts { get; }
private Blog() { }
public Blog(string name)
{
Name = name;
}
}
public class Comment
{
public int Id { get; set; }
public string Text { get; set; }
public Post Post { get; set; }
}
SELECT N+1
var posts = context.Posts.ToList();
//SELECT * FROM Posts
foreach (var post in posts)
{
var commentsCount = context.Comments
.Count(x => !x.IsDeleted && x.Post.Id == post.Id);
//SELECT COUNT(1) FROM Comments WHERE IsDeleted = 0 AND PostId = {0}
}
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
SELECT N+1
posts = context.Posts.Include(x => x.Comments).ToList();
//SELECT * FROM Posts WHERE IsDeleted = 0
//SELECT * FROM Comments
//INNER JOIN (SELECT Id FROM Posts WHERE IsDeleted = 0) AS T ON PostId = T.Id
foreach (var post in posts)
{
var commentsCount = post.Comments.Count();
}
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
SELECT N+1
var posts3 = context.Posts.Select(x => new
{
PostTitle = x.Title,
PostId = x.Id,
CommentsCount = x.Comments.Count(),
}).ToList();
//SELECT Title, Id, (SELECT COUNT(*)
//FROM Comments AS c WHERE [x].[Id] = [c].[PostId]) AS CommentsCount
//FROM Posts AS x
foreach (var post in posts3)
{
var commentsCount = post.CommentsCount;
}
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
SELECT N+1
var posts4 = context.Posts.Select(x => new
{
Post = x,
CommentsCount = x.Comments.Count(),
}).ToList();
//SELECT * FROM Posts
//SELECT Count(*) FROM Comments WHERE PostId = {0}
foreach (var post in posts3)
{
var commentsCount = post.CommentsCount;
}
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
SELECT N+1
var posts5 = context.Posts.Select(x => new
{
PostId = x.Id,
Blog = x.Blog,
CommentsCount = x.Comments.Count(),
}).ToList();
//SELECT [Blogs].*, (SELECT COUNT(*) FROM[Comments] AS[c]
//WHERE[x].[Id] = [c].[PostId] ) AS[CommentsCount]
//FROM[Posts] AS[x]
//LEFT JOIN[Blogs] AS[x.Blog] ON[x].[BlogId] = [x.Blog].[Id]
foreach (var post in posts3)
{
var commentsCount = post.CommentsCount;
}
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
Change Tracker
context = _createDatabase();
var blog = context.Blogs.FirstOrDefault();
Assert.Null(blog.Posts);
context.Posts.Where(x => x.BlogId == blog.Id).ToList();
Assert.Null(blog.Posts);
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
ToList()
var blog = context.Blogs.Include(x => x.TimeRegion).ToList();
//SELECT * FROM Blogs
//LEFT JOIN TimeRegion ON TimeRegion.Id = Blogs.TimeRegionId
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
context.TimeRegions.ToList();
var blog = context.Blogs.ToList();
//SELECT * FROM TimeRegions
//SELECT * FROM Blogs
GroupBy
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
var result = context.Posts
.GroupBy(p => p.BlogId)
.Select(g => new { BlogId = g.Key, PostCount = g.Count() })
.ToList();
//SELECT[p].[BlogId] AS[BID], COUNT(*) AS[cnt]
//FROM[Posts] AS[p]
//GROUP BY[p].[BlogId]
GroupBy
var optionsBuilder = new DbContextOptionsBuilder<MyContext>()
.ConfigureWarnings(x => x.Throw(RelationalEventId.QueryClientEvaluationWarning));
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
var result = context.Posts
.GroupBy(p => p.BlogId)
.Select(g => new { BID = g.Key, cnt = g.Count(x => !x.IsDeleted) })
.ToList();
var result = context.Posts
.GroupBy(p => p.Blog)
.Select(g => new { Url = g.Key.Name, Count = g.Count() })
.ToList();
Aggregates
var data = context.Blogs.Select(x => new
{
x.Id,
MaxPostId = x.Posts.Max(post => post.Id)
}).ToList();
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
InvalidOperationException: Sequence contains no elements.
Microsoft.EntityFrameworkCore.Query.QueryMethodProvider.GetResult<TResult>(IEnumerable
<ValueBuffer> valueBuffers, bool throwOnNullResult)
Min/Max/Average
var data = context.Blogs.Select(x => new
{
x.Id,
MaxPostId = x.Posts.Max(post => (int?)post.Id)
}).ToList();
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
Tired? 
Private constructors & Collection initializers
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
public class Blog
{
public int Id { get; private set; }
public string Name { get; set; }
private Blog() { }
public Blog(string name)
{
Name = name;
}
}
Private constructors & Collection initializers
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
public class Blog
{
public int Id { get; private set; }
public ICollection<Post> Posts { get; }
= new List<Post>(); //don't do that
}
var blog = context.Blogs.FirstOrDefault();
var postCount = blog.Posts.Count();
Lazy Loading
• Since 2.1
• No private constructors (but could be protected)
• Not recommended
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
var optionsBuilder = new DbContextOptionsBuilder<MyContext>()
.UseLazyLoadingProxies();
var blog = context.Blogs.FirstOrDefault();
//SELECT * FROM Blogs LIMIT 1
var postCount = blog.Posts.Count();
// SELECT * FROM Posts WHERE BlogId = 1
Target Multiple Databases
public abstract class MainContext : DbContext
{
public DbSet<Comment> Comments { get; set; }
protected MainContext(DbContextOptions<MainContext> options) : base(options) { }
}
public class PostgresContext : MainContext
{
public PostgresContext(DbContextOptions<MainContext> options) : base(options) { }
}
public class SqlServerContext : MainContext
{
public SqlServerContext(DbContextOptions<MainContext> options) : base(options) { }
}
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
Migrations.Designer.cs (could be deleted)
[Migration("20181124143113_Initial")]
partial class Initial
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.2.0-preview3-35497")
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("XUnitTestProject1.Blog", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>("Name");
b.HasKey("Id");
b.ToTable("Blogs");
});
modelBuilder.Entity("XUnitTestProject1.Comment", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<bool>("IsDeleted");
b.Property<int?>("PostId");
b.Property<string>("Text");
b.HasKey("Id");
b.HasIndex("PostId");
b.ToTable("Comments");
});
Value Convertors
• EnumToStringConverter
• DateTimeToTicksConverter
• Objects as JSON serialized string
(not built-in)
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
Value Convertors (JSON serialized-objects)
public class Blog {
public int Id { get; private set; }
…
public BlogSettings Settings { get; set; }
}
public class BlogSettings {
public int BackgroundColor { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.Entity<Blog>().Property(e => e.Settings)
.HasConversion(
v => JsonConvert.SerializeObject(v),
v => JsonConvert.DeserializeObject<BlogSettings>(v));
}
Query Filter (Soft Delete)
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.Entity<Post>().HasQueryFilter(p => !p.IsDeleted);
}
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
var blogs = context.Posts.ToList();
//SELECT * FROM Posts WHERE IsDeleted = 0
public class Post
{
public int Id { get; private set; }
public string Title { get; set; }
public Blog Blog { get; set; }
public bool IsDeleted { get; set; }
}
Testing
In Memory
var options = new DbContextOptionsBuilder<MyContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.Options;
_createDatabase = () => new MyContext(options);
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
In Memory & transactions
var options = new DbContextOptionsBuilder<MyContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.ConfigureWarnings(x =>
x.Ignore(InMemoryEventId.TransactionIgnoredWarning))
.Options;
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
In Memory & constraints??? SQLite!
var connection = new SqliteConnection("DataSource=:memory:");
connection.Open(); //an open connection is required for database to exist
var optionsBuilder = new DbContextOptionsBuilder<MyContext>()
.ConfigureWarnings(x =>
x.Throw(RelationalEventId.QueryClientEvaluationWarning))
.UseLazyLoadingProxies()
;
var options = optionsBuilder.UseSqlite(connection).Options;
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
Migrations
[Fact]
public void Migrations_RunAll_MigrationsSuccessfullyApplied()
{
using (var connection = new SqliteConnection("DataSource=:memory:"))
{
connection.Open(); //an open connection is required for database to exist
var optionsBuilder = new DbContextOptionsBuilder<MyContext>();
var options = optionsBuilder.UseSqlite(connection).Options;
var context = new MyContext(options);
context.Database.Migrate();
}
}
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
Migrations
var context = new MyContext(options);
context.Database.Migrate();
foreach (var entityType in context.Model.GetEntityTypes())
{
GetDbSet(context, entityType.ClrType).First();
}
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
System.InvalidOperationException : Error querying entity 'Post': SQLite Error 1: 'no
such column: p.Date'.
Integration
Z.EntityFramework.Plus.EFCore – Bulk Operations
_dbContext.Comments.Where(x => !x.IsDeleted)
.Update(x => new Comment()
{
IsDeleted = true,
});
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
UPDATE A
SET A.[IsDeleted] = @zzz_BatchUpdate_0
FROM[Comments] AS A
INNER JOIN(SELECT[x].[Id], [x].[IsDeleted],
[x].[PostId], [x].[Text]
FROM [Comments] AS [x]
WHERE [x].[IsDeleted] = 0
) AS B ON A.[Id] = B.[Id]
BulkUpdate does not work with InMemoryDatabase
Z.EntityFramework.Plus.EFCore – FromCache
var timeRegions = _dbContext.TimeRegions.FromCache();
_dbContext.AttachRange(timeRegions);
var blogs = _dbContext.Blogs.ToList();
Console.WriteLine(string.Join(", ", blogs.Select(blog => $"{blog.Name}:
{blog.TimeRegion.Offset}")));
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
Dapper (EFSqlTranslator)
var query = context.Posts
.Select(p => new
{
BlogId = p.Blog.Id,
Title = p.Title
})
.GroupBy(x => x.BlogId)
.Select(x => new { Id = x.Key, Cnt = x.Count() });
var queryResult = context.Query(query,
new EFModelInfoProvider(context),
new SqliteObjectFactory(),
out var sql);
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
Override SaveChanges
• Watch changes (e.g. cache invalidation)
• Log changes (e.g. audit)
• Inform about changes (send to 3rd party)
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
Override SaveChanges & SignalR
FullText Search
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
Summary
• SELECT N+1
• Group By & Aggregate
• ChangeTracker
• SaveChanges() override
• Testing & Migrations
E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
Спасибо. Вопросы?
Артур Дробинский
artur.drobinskiy@mcc-tomsk.de
http://arturdr.ru
До встречи 31 января!
TomskDotNet #2!
Точка Кипения
31 января, 18:30

Weitere ähnliche Inhalte

Was ist angesagt?

Custom YUI Widgets
Custom YUI WidgetsCustom YUI Widgets
Custom YUI Widgetscyrildoussin
 
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6Dmitry Soshnikov
 
TDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDB
TDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDBTDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDB
TDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDBtdc-globalcode
 
ESNext for humans - LvivJS 16 August 2014
ESNext for humans - LvivJS 16 August 2014ESNext for humans - LvivJS 16 August 2014
ESNext for humans - LvivJS 16 August 2014Jan Jongboom
 
Python 표준 라이브러리
Python 표준 라이브러리Python 표준 라이브러리
Python 표준 라이브러리용 최
 
Python dictionary : past, present, future
Python dictionary: past, present, futurePython dictionary: past, present, future
Python dictionary : past, present, futuredelimitry
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologyDaniel Knell
 
The Ring programming language version 1.6 book - Part 46 of 189
The Ring programming language version 1.6 book - Part 46 of 189The Ring programming language version 1.6 book - Part 46 of 189
The Ring programming language version 1.6 book - Part 46 of 189Mahmoud Samir Fayed
 
5. Ввод-вывод, доступ к файловой системе
5. Ввод-вывод, доступ к файловой системе5. Ввод-вывод, доступ к файловой системе
5. Ввод-вывод, доступ к файловой системеDEVTYPE
 
Using Fuzzy Code Search to Link Code Fragments in Discussions to Source Code
Using Fuzzy Code Search to Link Code Fragments in Discussions to Source CodeUsing Fuzzy Code Search to Link Code Fragments in Discussions to Source Code
Using Fuzzy Code Search to Link Code Fragments in Discussions to Source CodeNicolas Bettenburg
 
DEF CON 27 -OMER GULL - select code execution from using sq lite
DEF CON 27 -OMER GULL - select code execution from using sq liteDEF CON 27 -OMER GULL - select code execution from using sq lite
DEF CON 27 -OMER GULL - select code execution from using sq liteFelipe Prado
 
The Ring programming language version 1.2 book - Part 32 of 84
The Ring programming language version 1.2 book - Part 32 of 84The Ring programming language version 1.2 book - Part 32 of 84
The Ring programming language version 1.2 book - Part 32 of 84Mahmoud Samir Fayed
 
From java to kotlin beyond alt+shift+cmd+k - Droidcon italy
From java to kotlin beyond alt+shift+cmd+k - Droidcon italyFrom java to kotlin beyond alt+shift+cmd+k - Droidcon italy
From java to kotlin beyond alt+shift+cmd+k - Droidcon italyFabio Collini
 

Was ist angesagt? (20)

Custom YUI Widgets
Custom YUI WidgetsCustom YUI Widgets
Custom YUI Widgets
 
Why Learn Python?
Why Learn Python?Why Learn Python?
Why Learn Python?
 
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6
 
Xm lparsers
Xm lparsersXm lparsers
Xm lparsers
 
TDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDB
TDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDBTDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDB
TDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDB
 
Intro
IntroIntro
Intro
 
ESNext for humans - LvivJS 16 August 2014
ESNext for humans - LvivJS 16 August 2014ESNext for humans - LvivJS 16 August 2014
ESNext for humans - LvivJS 16 August 2014
 
Python 표준 라이브러리
Python 표준 라이브러리Python 표준 라이브러리
Python 표준 라이브러리
 
Python dictionary : past, present, future
Python dictionary: past, present, futurePython dictionary: past, present, future
Python dictionary : past, present, future
 
H base programming
H base programmingH base programming
H base programming
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technology
 
The Ring programming language version 1.6 book - Part 46 of 189
The Ring programming language version 1.6 book - Part 46 of 189The Ring programming language version 1.6 book - Part 46 of 189
The Ring programming language version 1.6 book - Part 46 of 189
 
PHP 5.4
PHP 5.4PHP 5.4
PHP 5.4
 
Why Sifu
Why SifuWhy Sifu
Why Sifu
 
5. Ввод-вывод, доступ к файловой системе
5. Ввод-вывод, доступ к файловой системе5. Ввод-вывод, доступ к файловой системе
5. Ввод-вывод, доступ к файловой системе
 
Using Fuzzy Code Search to Link Code Fragments in Discussions to Source Code
Using Fuzzy Code Search to Link Code Fragments in Discussions to Source CodeUsing Fuzzy Code Search to Link Code Fragments in Discussions to Source Code
Using Fuzzy Code Search to Link Code Fragments in Discussions to Source Code
 
Sam wd programs
Sam wd programsSam wd programs
Sam wd programs
 
DEF CON 27 -OMER GULL - select code execution from using sq lite
DEF CON 27 -OMER GULL - select code execution from using sq liteDEF CON 27 -OMER GULL - select code execution from using sq lite
DEF CON 27 -OMER GULL - select code execution from using sq lite
 
The Ring programming language version 1.2 book - Part 32 of 84
The Ring programming language version 1.2 book - Part 32 of 84The Ring programming language version 1.2 book - Part 32 of 84
The Ring programming language version 1.2 book - Part 32 of 84
 
From java to kotlin beyond alt+shift+cmd+k - Droidcon italy
From java to kotlin beyond alt+shift+cmd+k - Droidcon italyFrom java to kotlin beyond alt+shift+cmd+k - Droidcon italy
From java to kotlin beyond alt+shift+cmd+k - Droidcon italy
 

Ähnlich wie Entity Framework Core: tips and tricks

Building a friendly .NET SDK to connect to Space
Building a friendly .NET SDK to connect to SpaceBuilding a friendly .NET SDK to connect to Space
Building a friendly .NET SDK to connect to SpaceMaarten Balliauw
 
Web CrawlersrcedusmulylecrawlerController.javaWeb Crawler.docx
Web CrawlersrcedusmulylecrawlerController.javaWeb Crawler.docxWeb CrawlersrcedusmulylecrawlerController.javaWeb Crawler.docx
Web CrawlersrcedusmulylecrawlerController.javaWeb Crawler.docxcelenarouzie
 
Micro-ORM Introduction - Don't overcomplicate
Micro-ORM Introduction - Don't overcomplicateMicro-ORM Introduction - Don't overcomplicate
Micro-ORM Introduction - Don't overcomplicateKiev ALT.NET
 
4Developers 2018: Ile (nie) wiesz o strukturach w .NET (Łukasz Pyrzyk)
4Developers 2018: Ile (nie) wiesz o strukturach w .NET (Łukasz Pyrzyk)4Developers 2018: Ile (nie) wiesz o strukturach w .NET (Łukasz Pyrzyk)
4Developers 2018: Ile (nie) wiesz o strukturach w .NET (Łukasz Pyrzyk)PROIDEA
 
.NET Fest 2017. Михаил Щербаков. Механизмы предотвращения атак в ASP.NET Core
.NET Fest 2017. Михаил Щербаков. Механизмы предотвращения атак в ASP.NET Core.NET Fest 2017. Михаил Щербаков. Механизмы предотвращения атак в ASP.NET Core
.NET Fest 2017. Михаил Щербаков. Механизмы предотвращения атак в ASP.NET CoreNETFest
 
SummaryHW6 Account ManagementIn HW4, you kept track of multiple.pdf
SummaryHW6 Account ManagementIn HW4, you kept track of multiple.pdfSummaryHW6 Account ManagementIn HW4, you kept track of multiple.pdf
SummaryHW6 Account ManagementIn HW4, you kept track of multiple.pdfARORACOCKERY2111
 
Web весна 2013 лекция 6
Web весна 2013 лекция 6Web весна 2013 лекция 6
Web весна 2013 лекция 6Technopark
 
C# 6.0 - April 2014 preview
C# 6.0 - April 2014 previewC# 6.0 - April 2014 preview
C# 6.0 - April 2014 previewPaulo Morgado
 
#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기Arawn Park
 
Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Juan Pablo
 
Embedded Typesafe Domain Specific Languages for Java
Embedded Typesafe Domain Specific Languages for JavaEmbedded Typesafe Domain Specific Languages for Java
Embedded Typesafe Domain Specific Languages for JavaJevgeni Kabanov
 

Ähnlich wie Entity Framework Core: tips and tricks (20)

greenDAO
greenDAOgreenDAO
greenDAO
 
Building a friendly .NET SDK to connect to Space
Building a friendly .NET SDK to connect to SpaceBuilding a friendly .NET SDK to connect to Space
Building a friendly .NET SDK to connect to Space
 
Web CrawlersrcedusmulylecrawlerController.javaWeb Crawler.docx
Web CrawlersrcedusmulylecrawlerController.javaWeb Crawler.docxWeb CrawlersrcedusmulylecrawlerController.javaWeb Crawler.docx
Web CrawlersrcedusmulylecrawlerController.javaWeb Crawler.docx
 
C# labprograms
C# labprogramsC# labprograms
C# labprograms
 
Micro-ORM Introduction - Don't overcomplicate
Micro-ORM Introduction - Don't overcomplicateMicro-ORM Introduction - Don't overcomplicate
Micro-ORM Introduction - Don't overcomplicate
 
3 database-jdbc(1)
3 database-jdbc(1)3 database-jdbc(1)
3 database-jdbc(1)
 
TechTalk - Dotnet
TechTalk - DotnetTechTalk - Dotnet
TechTalk - Dotnet
 
PostThis
PostThisPostThis
PostThis
 
4Developers 2018: Ile (nie) wiesz o strukturach w .NET (Łukasz Pyrzyk)
4Developers 2018: Ile (nie) wiesz o strukturach w .NET (Łukasz Pyrzyk)4Developers 2018: Ile (nie) wiesz o strukturach w .NET (Łukasz Pyrzyk)
4Developers 2018: Ile (nie) wiesz o strukturach w .NET (Łukasz Pyrzyk)
 
.NET Fest 2017. Михаил Щербаков. Механизмы предотвращения атак в ASP.NET Core
.NET Fest 2017. Михаил Щербаков. Механизмы предотвращения атак в ASP.NET Core.NET Fest 2017. Михаил Щербаков. Механизмы предотвращения атак в ASP.NET Core
.NET Fest 2017. Михаил Щербаков. Механизмы предотвращения атак в ASP.NET Core
 
SummaryHW6 Account ManagementIn HW4, you kept track of multiple.pdf
SummaryHW6 Account ManagementIn HW4, you kept track of multiple.pdfSummaryHW6 Account ManagementIn HW4, you kept track of multiple.pdf
SummaryHW6 Account ManagementIn HW4, you kept track of multiple.pdf
 
Green dao
Green daoGreen dao
Green dao
 
Web весна 2013 лекция 6
Web весна 2013 лекция 6Web весна 2013 лекция 6
Web весна 2013 лекция 6
 
Clean Code
Clean CodeClean Code
Clean Code
 
srgoc
srgocsrgoc
srgoc
 
C# 6.0 - April 2014 preview
C# 6.0 - April 2014 previewC# 6.0 - April 2014 preview
C# 6.0 - April 2014 preview
 
#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기
 
Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#
 
Embedded Typesafe Domain Specific Languages for Java
Embedded Typesafe Domain Specific Languages for JavaEmbedded Typesafe Domain Specific Languages for Java
Embedded Typesafe Domain Specific Languages for Java
 
Clean code
Clean codeClean code
Clean code
 

Kürzlich hochgeladen

Kodo Millet PPT made by Ghanshyam bairwa college of Agriculture kumher bhara...
Kodo Millet  PPT made by Ghanshyam bairwa college of Agriculture kumher bhara...Kodo Millet  PPT made by Ghanshyam bairwa college of Agriculture kumher bhara...
Kodo Millet PPT made by Ghanshyam bairwa college of Agriculture kumher bhara...pradhanghanshyam7136
 
Basic Civil Engineering first year Notes- Chapter 4 Building.pptx
Basic Civil Engineering first year Notes- Chapter 4 Building.pptxBasic Civil Engineering first year Notes- Chapter 4 Building.pptx
Basic Civil Engineering first year Notes- Chapter 4 Building.pptxDenish Jangid
 
This PowerPoint helps students to consider the concept of infinity.
This PowerPoint helps students to consider the concept of infinity.This PowerPoint helps students to consider the concept of infinity.
This PowerPoint helps students to consider the concept of infinity.christianmathematics
 
Sociology 101 Demonstration of Learning Exhibit
Sociology 101 Demonstration of Learning ExhibitSociology 101 Demonstration of Learning Exhibit
Sociology 101 Demonstration of Learning Exhibitjbellavia9
 
COMMUNICATING NEGATIVE NEWS - APPROACHES .pptx
COMMUNICATING NEGATIVE NEWS - APPROACHES .pptxCOMMUNICATING NEGATIVE NEWS - APPROACHES .pptx
COMMUNICATING NEGATIVE NEWS - APPROACHES .pptxannathomasp01
 
HMCS Vancouver Pre-Deployment Brief - May 2024 (Web Version).pptx
HMCS Vancouver Pre-Deployment Brief - May 2024 (Web Version).pptxHMCS Vancouver Pre-Deployment Brief - May 2024 (Web Version).pptx
HMCS Vancouver Pre-Deployment Brief - May 2024 (Web Version).pptxmarlenawright1
 
Fostering Friendships - Enhancing Social Bonds in the Classroom
Fostering Friendships - Enhancing Social Bonds  in the ClassroomFostering Friendships - Enhancing Social Bonds  in the Classroom
Fostering Friendships - Enhancing Social Bonds in the ClassroomPooky Knightsmith
 
On_Translating_a_Tamil_Poem_by_A_K_Ramanujan.pptx
On_Translating_a_Tamil_Poem_by_A_K_Ramanujan.pptxOn_Translating_a_Tamil_Poem_by_A_K_Ramanujan.pptx
On_Translating_a_Tamil_Poem_by_A_K_Ramanujan.pptxPooja Bhuva
 
ICT Role in 21st Century Education & its Challenges.pptx
ICT Role in 21st Century Education & its Challenges.pptxICT Role in 21st Century Education & its Challenges.pptx
ICT Role in 21st Century Education & its Challenges.pptxAreebaZafar22
 
How to Add New Custom Addons Path in Odoo 17
How to Add New Custom Addons Path in Odoo 17How to Add New Custom Addons Path in Odoo 17
How to Add New Custom Addons Path in Odoo 17Celine George
 
Exploring_the_Narrative_Style_of_Amitav_Ghoshs_Gun_Island.pptx
Exploring_the_Narrative_Style_of_Amitav_Ghoshs_Gun_Island.pptxExploring_the_Narrative_Style_of_Amitav_Ghoshs_Gun_Island.pptx
Exploring_the_Narrative_Style_of_Amitav_Ghoshs_Gun_Island.pptxPooja Bhuva
 
Sensory_Experience_and_Emotional_Resonance_in_Gabriel_Okaras_The_Piano_and_Th...
Sensory_Experience_and_Emotional_Resonance_in_Gabriel_Okaras_The_Piano_and_Th...Sensory_Experience_and_Emotional_Resonance_in_Gabriel_Okaras_The_Piano_and_Th...
Sensory_Experience_and_Emotional_Resonance_in_Gabriel_Okaras_The_Piano_and_Th...Pooja Bhuva
 
How to Manage Global Discount in Odoo 17 POS
How to Manage Global Discount in Odoo 17 POSHow to Manage Global Discount in Odoo 17 POS
How to Manage Global Discount in Odoo 17 POSCeline George
 
How to Give a Domain for a Field in Odoo 17
How to Give a Domain for a Field in Odoo 17How to Give a Domain for a Field in Odoo 17
How to Give a Domain for a Field in Odoo 17Celine George
 
How to Create and Manage Wizard in Odoo 17
How to Create and Manage Wizard in Odoo 17How to Create and Manage Wizard in Odoo 17
How to Create and Manage Wizard in Odoo 17Celine George
 
Understanding Accommodations and Modifications
Understanding  Accommodations and ModificationsUnderstanding  Accommodations and Modifications
Understanding Accommodations and ModificationsMJDuyan
 
On National Teacher Day, meet the 2024-25 Kenan Fellows
On National Teacher Day, meet the 2024-25 Kenan FellowsOn National Teacher Day, meet the 2024-25 Kenan Fellows
On National Teacher Day, meet the 2024-25 Kenan FellowsMebane Rash
 
TỔNG ÔN TẬP THI VÀO LỚP 10 MÔN TIẾNG ANH NĂM HỌC 2023 - 2024 CÓ ĐÁP ÁN (NGỮ Â...
TỔNG ÔN TẬP THI VÀO LỚP 10 MÔN TIẾNG ANH NĂM HỌC 2023 - 2024 CÓ ĐÁP ÁN (NGỮ Â...TỔNG ÔN TẬP THI VÀO LỚP 10 MÔN TIẾNG ANH NĂM HỌC 2023 - 2024 CÓ ĐÁP ÁN (NGỮ Â...
TỔNG ÔN TẬP THI VÀO LỚP 10 MÔN TIẾNG ANH NĂM HỌC 2023 - 2024 CÓ ĐÁP ÁN (NGỮ Â...Nguyen Thanh Tu Collection
 
HMCS Max Bernays Pre-Deployment Brief (May 2024).pptx
HMCS Max Bernays Pre-Deployment Brief (May 2024).pptxHMCS Max Bernays Pre-Deployment Brief (May 2024).pptx
HMCS Max Bernays Pre-Deployment Brief (May 2024).pptxEsquimalt MFRC
 
Food safety_Challenges food safety laboratories_.pdf
Food safety_Challenges food safety laboratories_.pdfFood safety_Challenges food safety laboratories_.pdf
Food safety_Challenges food safety laboratories_.pdfSherif Taha
 

Kürzlich hochgeladen (20)

Kodo Millet PPT made by Ghanshyam bairwa college of Agriculture kumher bhara...
Kodo Millet  PPT made by Ghanshyam bairwa college of Agriculture kumher bhara...Kodo Millet  PPT made by Ghanshyam bairwa college of Agriculture kumher bhara...
Kodo Millet PPT made by Ghanshyam bairwa college of Agriculture kumher bhara...
 
Basic Civil Engineering first year Notes- Chapter 4 Building.pptx
Basic Civil Engineering first year Notes- Chapter 4 Building.pptxBasic Civil Engineering first year Notes- Chapter 4 Building.pptx
Basic Civil Engineering first year Notes- Chapter 4 Building.pptx
 
This PowerPoint helps students to consider the concept of infinity.
This PowerPoint helps students to consider the concept of infinity.This PowerPoint helps students to consider the concept of infinity.
This PowerPoint helps students to consider the concept of infinity.
 
Sociology 101 Demonstration of Learning Exhibit
Sociology 101 Demonstration of Learning ExhibitSociology 101 Demonstration of Learning Exhibit
Sociology 101 Demonstration of Learning Exhibit
 
COMMUNICATING NEGATIVE NEWS - APPROACHES .pptx
COMMUNICATING NEGATIVE NEWS - APPROACHES .pptxCOMMUNICATING NEGATIVE NEWS - APPROACHES .pptx
COMMUNICATING NEGATIVE NEWS - APPROACHES .pptx
 
HMCS Vancouver Pre-Deployment Brief - May 2024 (Web Version).pptx
HMCS Vancouver Pre-Deployment Brief - May 2024 (Web Version).pptxHMCS Vancouver Pre-Deployment Brief - May 2024 (Web Version).pptx
HMCS Vancouver Pre-Deployment Brief - May 2024 (Web Version).pptx
 
Fostering Friendships - Enhancing Social Bonds in the Classroom
Fostering Friendships - Enhancing Social Bonds  in the ClassroomFostering Friendships - Enhancing Social Bonds  in the Classroom
Fostering Friendships - Enhancing Social Bonds in the Classroom
 
On_Translating_a_Tamil_Poem_by_A_K_Ramanujan.pptx
On_Translating_a_Tamil_Poem_by_A_K_Ramanujan.pptxOn_Translating_a_Tamil_Poem_by_A_K_Ramanujan.pptx
On_Translating_a_Tamil_Poem_by_A_K_Ramanujan.pptx
 
ICT Role in 21st Century Education & its Challenges.pptx
ICT Role in 21st Century Education & its Challenges.pptxICT Role in 21st Century Education & its Challenges.pptx
ICT Role in 21st Century Education & its Challenges.pptx
 
How to Add New Custom Addons Path in Odoo 17
How to Add New Custom Addons Path in Odoo 17How to Add New Custom Addons Path in Odoo 17
How to Add New Custom Addons Path in Odoo 17
 
Exploring_the_Narrative_Style_of_Amitav_Ghoshs_Gun_Island.pptx
Exploring_the_Narrative_Style_of_Amitav_Ghoshs_Gun_Island.pptxExploring_the_Narrative_Style_of_Amitav_Ghoshs_Gun_Island.pptx
Exploring_the_Narrative_Style_of_Amitav_Ghoshs_Gun_Island.pptx
 
Sensory_Experience_and_Emotional_Resonance_in_Gabriel_Okaras_The_Piano_and_Th...
Sensory_Experience_and_Emotional_Resonance_in_Gabriel_Okaras_The_Piano_and_Th...Sensory_Experience_and_Emotional_Resonance_in_Gabriel_Okaras_The_Piano_and_Th...
Sensory_Experience_and_Emotional_Resonance_in_Gabriel_Okaras_The_Piano_and_Th...
 
How to Manage Global Discount in Odoo 17 POS
How to Manage Global Discount in Odoo 17 POSHow to Manage Global Discount in Odoo 17 POS
How to Manage Global Discount in Odoo 17 POS
 
How to Give a Domain for a Field in Odoo 17
How to Give a Domain for a Field in Odoo 17How to Give a Domain for a Field in Odoo 17
How to Give a Domain for a Field in Odoo 17
 
How to Create and Manage Wizard in Odoo 17
How to Create and Manage Wizard in Odoo 17How to Create and Manage Wizard in Odoo 17
How to Create and Manage Wizard in Odoo 17
 
Understanding Accommodations and Modifications
Understanding  Accommodations and ModificationsUnderstanding  Accommodations and Modifications
Understanding Accommodations and Modifications
 
On National Teacher Day, meet the 2024-25 Kenan Fellows
On National Teacher Day, meet the 2024-25 Kenan FellowsOn National Teacher Day, meet the 2024-25 Kenan Fellows
On National Teacher Day, meet the 2024-25 Kenan Fellows
 
TỔNG ÔN TẬP THI VÀO LỚP 10 MÔN TIẾNG ANH NĂM HỌC 2023 - 2024 CÓ ĐÁP ÁN (NGỮ Â...
TỔNG ÔN TẬP THI VÀO LỚP 10 MÔN TIẾNG ANH NĂM HỌC 2023 - 2024 CÓ ĐÁP ÁN (NGỮ Â...TỔNG ÔN TẬP THI VÀO LỚP 10 MÔN TIẾNG ANH NĂM HỌC 2023 - 2024 CÓ ĐÁP ÁN (NGỮ Â...
TỔNG ÔN TẬP THI VÀO LỚP 10 MÔN TIẾNG ANH NĂM HỌC 2023 - 2024 CÓ ĐÁP ÁN (NGỮ Â...
 
HMCS Max Bernays Pre-Deployment Brief (May 2024).pptx
HMCS Max Bernays Pre-Deployment Brief (May 2024).pptxHMCS Max Bernays Pre-Deployment Brief (May 2024).pptx
HMCS Max Bernays Pre-Deployment Brief (May 2024).pptx
 
Food safety_Challenges food safety laboratories_.pdf
Food safety_Challenges food safety laboratories_.pdfFood safety_Challenges food safety laboratories_.pdf
Food safety_Challenges food safety laboratories_.pdf
 

Entity Framework Core: tips and tricks

  • 2. About Us MCC Tomsk Cloud platform for tele-medicine Microservices Message Broker SOA .Net Core React/Redux E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
  • 3. E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
  • 4. E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
  • 5. E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
  • 6. E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
  • 7. using (SqlConnection connection = new SqlConnection(connectionString)) { SqlCommand command = new SqlCommand(queryString, connection); connection.Open(); SqlDataReader reader = command.ExecuteReader(); reader.Read(); Console.WriteLine("t{0}t{1}t{2}", reader[0], reader[1], reader[2]); } public class Comment { public int Id { get; set; } public string Text { get; set; } public bool IsDeleted { get; set; } public Post Post { get; set; } } var context = new MyContext(options); var comment = context.Comments.First(); Console.WriteLine("t{0}t{1}", comment.Text, comment.Id);
  • 8. var context = new MyContext(options); var comment = context.Comments .Include(x => x.Post) .Where(x => x.Id > 5) .Where(x => !x.Post.IsDeleted) .OrderBy(x => x.Text) .First(); Console.WriteLine("t{0}t{1}", comment.Post.Title, comment.Text); var sql = @"select * from #Posts p left join #Users u on u.Id = p.OwnerId Order by p.Id"; var data = connection.Query<Post, User, Post>(sql, (post, user) => { post.Owner = user; return post; }); var post = data.First();
  • 10. Entities public class Post { public int Id { get; private set; } public string Title { get; set; } public Blog Blog { get; set; } public bool IsDeleted { get; set; } } E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s public class Blog { public int Id { get; private set; } public string Name { get; set; } public ICollection<Post> Posts { get; } private Blog() { } public Blog(string name) { Name = name; } } public class Comment { public int Id { get; set; } public string Text { get; set; } public Post Post { get; set; } }
  • 11. SELECT N+1 var posts = context.Posts.ToList(); //SELECT * FROM Posts foreach (var post in posts) { var commentsCount = context.Comments .Count(x => !x.IsDeleted && x.Post.Id == post.Id); //SELECT COUNT(1) FROM Comments WHERE IsDeleted = 0 AND PostId = {0} } E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
  • 12. SELECT N+1 posts = context.Posts.Include(x => x.Comments).ToList(); //SELECT * FROM Posts WHERE IsDeleted = 0 //SELECT * FROM Comments //INNER JOIN (SELECT Id FROM Posts WHERE IsDeleted = 0) AS T ON PostId = T.Id foreach (var post in posts) { var commentsCount = post.Comments.Count(); } E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
  • 13. SELECT N+1 var posts3 = context.Posts.Select(x => new { PostTitle = x.Title, PostId = x.Id, CommentsCount = x.Comments.Count(), }).ToList(); //SELECT Title, Id, (SELECT COUNT(*) //FROM Comments AS c WHERE [x].[Id] = [c].[PostId]) AS CommentsCount //FROM Posts AS x foreach (var post in posts3) { var commentsCount = post.CommentsCount; } E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
  • 14. SELECT N+1 var posts4 = context.Posts.Select(x => new { Post = x, CommentsCount = x.Comments.Count(), }).ToList(); //SELECT * FROM Posts //SELECT Count(*) FROM Comments WHERE PostId = {0} foreach (var post in posts3) { var commentsCount = post.CommentsCount; } E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
  • 15. SELECT N+1 var posts5 = context.Posts.Select(x => new { PostId = x.Id, Blog = x.Blog, CommentsCount = x.Comments.Count(), }).ToList(); //SELECT [Blogs].*, (SELECT COUNT(*) FROM[Comments] AS[c] //WHERE[x].[Id] = [c].[PostId] ) AS[CommentsCount] //FROM[Posts] AS[x] //LEFT JOIN[Blogs] AS[x.Blog] ON[x].[BlogId] = [x.Blog].[Id] foreach (var post in posts3) { var commentsCount = post.CommentsCount; } E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
  • 16. E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
  • 17. Change Tracker context = _createDatabase(); var blog = context.Blogs.FirstOrDefault(); Assert.Null(blog.Posts); context.Posts.Where(x => x.BlogId == blog.Id).ToList(); Assert.Null(blog.Posts); E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
  • 18. E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
  • 19. ToList() var blog = context.Blogs.Include(x => x.TimeRegion).ToList(); //SELECT * FROM Blogs //LEFT JOIN TimeRegion ON TimeRegion.Id = Blogs.TimeRegionId E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s context.TimeRegions.ToList(); var blog = context.Blogs.ToList(); //SELECT * FROM TimeRegions //SELECT * FROM Blogs
  • 20. GroupBy E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s var result = context.Posts .GroupBy(p => p.BlogId) .Select(g => new { BlogId = g.Key, PostCount = g.Count() }) .ToList(); //SELECT[p].[BlogId] AS[BID], COUNT(*) AS[cnt] //FROM[Posts] AS[p] //GROUP BY[p].[BlogId]
  • 21. GroupBy var optionsBuilder = new DbContextOptionsBuilder<MyContext>() .ConfigureWarnings(x => x.Throw(RelationalEventId.QueryClientEvaluationWarning)); E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s var result = context.Posts .GroupBy(p => p.BlogId) .Select(g => new { BID = g.Key, cnt = g.Count(x => !x.IsDeleted) }) .ToList(); var result = context.Posts .GroupBy(p => p.Blog) .Select(g => new { Url = g.Key.Name, Count = g.Count() }) .ToList();
  • 22. Aggregates var data = context.Blogs.Select(x => new { x.Id, MaxPostId = x.Posts.Max(post => post.Id) }).ToList(); E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s InvalidOperationException: Sequence contains no elements. Microsoft.EntityFrameworkCore.Query.QueryMethodProvider.GetResult<TResult>(IEnumerable <ValueBuffer> valueBuffers, bool throwOnNullResult)
  • 23. Min/Max/Average var data = context.Blogs.Select(x => new { x.Id, MaxPostId = x.Posts.Max(post => (int?)post.Id) }).ToList(); E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
  • 25. Private constructors & Collection initializers E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s public class Blog { public int Id { get; private set; } public string Name { get; set; } private Blog() { } public Blog(string name) { Name = name; } }
  • 26. Private constructors & Collection initializers E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s public class Blog { public int Id { get; private set; } public ICollection<Post> Posts { get; } = new List<Post>(); //don't do that } var blog = context.Blogs.FirstOrDefault(); var postCount = blog.Posts.Count();
  • 27. Lazy Loading • Since 2.1 • No private constructors (but could be protected) • Not recommended E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s var optionsBuilder = new DbContextOptionsBuilder<MyContext>() .UseLazyLoadingProxies(); var blog = context.Blogs.FirstOrDefault(); //SELECT * FROM Blogs LIMIT 1 var postCount = blog.Posts.Count(); // SELECT * FROM Posts WHERE BlogId = 1
  • 28. Target Multiple Databases public abstract class MainContext : DbContext { public DbSet<Comment> Comments { get; set; } protected MainContext(DbContextOptions<MainContext> options) : base(options) { } } public class PostgresContext : MainContext { public PostgresContext(DbContextOptions<MainContext> options) : base(options) { } } public class SqlServerContext : MainContext { public SqlServerContext(DbContextOptions<MainContext> options) : base(options) { } } E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
  • 29. Migrations.Designer.cs (could be deleted) [Migration("20181124143113_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder .HasAnnotation("ProductVersion", "2.2.0-preview3-35497") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); modelBuilder.Entity("XUnitTestProject1.Blog", b => { b.Property<int>("Id") .ValueGeneratedOnAdd() .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); b.Property<string>("Name"); b.HasKey("Id"); b.ToTable("Blogs"); }); modelBuilder.Entity("XUnitTestProject1.Comment", b => { b.Property<int>("Id") .ValueGeneratedOnAdd() .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); b.Property<bool>("IsDeleted"); b.Property<int?>("PostId"); b.Property<string>("Text"); b.HasKey("Id"); b.HasIndex("PostId"); b.ToTable("Comments"); });
  • 30. Value Convertors • EnumToStringConverter • DateTimeToTicksConverter • Objects as JSON serialized string (not built-in) E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
  • 31. Value Convertors (JSON serialized-objects) public class Blog { public int Id { get; private set; } … public BlogSettings Settings { get; set; } } public class BlogSettings { public int BackgroundColor { get; set; } } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>().Property(e => e.Settings) .HasConversion( v => JsonConvert.SerializeObject(v), v => JsonConvert.DeserializeObject<BlogSettings>(v)); }
  • 32. Query Filter (Soft Delete) protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Post>().HasQueryFilter(p => !p.IsDeleted); } E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s var blogs = context.Posts.ToList(); //SELECT * FROM Posts WHERE IsDeleted = 0 public class Post { public int Id { get; private set; } public string Title { get; set; } public Blog Blog { get; set; } public bool IsDeleted { get; set; } }
  • 34. In Memory var options = new DbContextOptionsBuilder<MyContext>() .UseInMemoryDatabase(Guid.NewGuid().ToString()) .Options; _createDatabase = () => new MyContext(options); E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
  • 35. In Memory & transactions var options = new DbContextOptionsBuilder<MyContext>() .UseInMemoryDatabase(Guid.NewGuid().ToString()) .ConfigureWarnings(x => x.Ignore(InMemoryEventId.TransactionIgnoredWarning)) .Options; E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
  • 36. In Memory & constraints??? SQLite! var connection = new SqliteConnection("DataSource=:memory:"); connection.Open(); //an open connection is required for database to exist var optionsBuilder = new DbContextOptionsBuilder<MyContext>() .ConfigureWarnings(x => x.Throw(RelationalEventId.QueryClientEvaluationWarning)) .UseLazyLoadingProxies() ; var options = optionsBuilder.UseSqlite(connection).Options; E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
  • 37. Migrations [Fact] public void Migrations_RunAll_MigrationsSuccessfullyApplied() { using (var connection = new SqliteConnection("DataSource=:memory:")) { connection.Open(); //an open connection is required for database to exist var optionsBuilder = new DbContextOptionsBuilder<MyContext>(); var options = optionsBuilder.UseSqlite(connection).Options; var context = new MyContext(options); context.Database.Migrate(); } } E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
  • 38. Migrations var context = new MyContext(options); context.Database.Migrate(); foreach (var entityType in context.Model.GetEntityTypes()) { GetDbSet(context, entityType.ClrType).First(); } E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s System.InvalidOperationException : Error querying entity 'Post': SQLite Error 1: 'no such column: p.Date'.
  • 40. Z.EntityFramework.Plus.EFCore – Bulk Operations _dbContext.Comments.Where(x => !x.IsDeleted) .Update(x => new Comment() { IsDeleted = true, }); E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s UPDATE A SET A.[IsDeleted] = @zzz_BatchUpdate_0 FROM[Comments] AS A INNER JOIN(SELECT[x].[Id], [x].[IsDeleted], [x].[PostId], [x].[Text] FROM [Comments] AS [x] WHERE [x].[IsDeleted] = 0 ) AS B ON A.[Id] = B.[Id] BulkUpdate does not work with InMemoryDatabase
  • 41. Z.EntityFramework.Plus.EFCore – FromCache var timeRegions = _dbContext.TimeRegions.FromCache(); _dbContext.AttachRange(timeRegions); var blogs = _dbContext.Blogs.ToList(); Console.WriteLine(string.Join(", ", blogs.Select(blog => $"{blog.Name}: {blog.TimeRegion.Offset}"))); E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
  • 42. Dapper (EFSqlTranslator) var query = context.Posts .Select(p => new { BlogId = p.Blog.Id, Title = p.Title }) .GroupBy(x => x.BlogId) .Select(x => new { Id = x.Key, Cnt = x.Count() }); var queryResult = context.Query(query, new EFModelInfoProvider(context), new SqliteObjectFactory(), out var sql); E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
  • 43. Override SaveChanges • Watch changes (e.g. cache invalidation) • Log changes (e.g. audit) • Inform about changes (send to 3rd party) E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
  • 45. FullText Search E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
  • 46. Summary • SELECT N+1 • Group By & Aggregate • ChangeTracker • SaveChanges() override • Testing & Migrations E n t i t y F r a m e w o r k C o r e : t i p s a n d t r i c k s
  • 48. До встречи 31 января! TomskDotNet #2! Точка Кипения 31 января, 18:30

Hinweis der Redaktion

  1. Сейчас я нарисую самую сложную архитектуру
  2. Сейчас я нарисую самую сложную архитектуру
  3. Сейчас я нарисую самую сложную архитектуру