-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Tweaks for by-convention mapping of gRPC model (#24553)
Fixes #23703 At some point we started eagerly throwing when attempting to build a setter delegate. This should be lazy because we don't always need a setter. Fixes #23901 Detects "propertyName_" as a backing field.
- Loading branch information
1 parent
34fa402
commit 304219c
Showing
9 changed files
with
307 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
21 changes: 21 additions & 0 deletions
21
test/EFCore.AspNet.InMemory.FunctionalTests/GrpcInMemoryTest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using Microsoft.EntityFrameworkCore.TestUtilities; | ||
|
||
namespace Microsoft.EntityFrameworkCore | ||
{ | ||
public class GrpcInMemoryTest : GrpcTestBase<GrpcInMemoryTest.GrpcInMemoryFixture> | ||
{ | ||
public GrpcInMemoryTest(GrpcInMemoryFixture fixture) | ||
: base(fixture) | ||
{ | ||
} | ||
|
||
public class GrpcInMemoryFixture : GrpcFixtureBase | ||
{ | ||
protected override ITestStoreFactory TestStoreFactory | ||
=> InMemoryTestStoreFactory.Instance; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using Google.Protobuf.WellKnownTypes; | ||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion; | ||
using Microsoft.EntityFrameworkCore.TestUtilities; | ||
using ProtoTest; | ||
using Xunit; | ||
|
||
namespace Microsoft.EntityFrameworkCore | ||
{ | ||
public abstract class GrpcTestBase<TFixture> : IClassFixture<TFixture> | ||
where TFixture : GrpcTestBase<TFixture>.GrpcFixtureBase | ||
{ | ||
protected GrpcTestBase(TFixture fixture) | ||
=> Fixture = fixture; | ||
|
||
protected TFixture Fixture { get; } | ||
|
||
protected List<EntityTypeMapping> ExpectedMappings | ||
=> new() | ||
{ | ||
new() | ||
{ | ||
Name = "PostTag", | ||
TableName = "PostTag", | ||
PrimaryKey = | ||
"Key: PostTag (Dictionary<string, object>).PostsInTagDataPostId, PostTag (Dictionary<string, object>).TagsInPostDataTagId PK", | ||
Properties = | ||
{ | ||
"Property: PostTag (Dictionary<string, object>).PostsInTagDataPostId (no field, int) Indexer Required PK FK AfterSave:Throw", | ||
"Property: PostTag (Dictionary<string, object>).TagsInPostDataTagId (no field, int) Indexer Required PK FK Index AfterSave:Throw", | ||
}, | ||
Indexes = { "{'TagsInPostDataTagId'} ", }, | ||
FKs = | ||
{ | ||
"ForeignKey: PostTag (Dictionary<string, object>) {'PostsInTagDataPostId'} -> Post {'PostId'} Cascade", | ||
"ForeignKey: PostTag (Dictionary<string, object>) {'TagsInPostDataTagId'} -> Tag {'TagId'} Cascade", | ||
}, | ||
}, | ||
new() | ||
{ | ||
Name = "ProtoTest.Author", | ||
TableName = "Author", | ||
PrimaryKey = "Key: Author.AuthorId PK", | ||
Properties = | ||
{ | ||
"Property: Author.AuthorId (authorId_, int) Required PK AfterSave:Throw ValueGenerated.OnAdd", | ||
"Property: Author.DateCreated (dateCreated_, Timestamp)", | ||
"Property: Author.Name (name_, string)", | ||
}, | ||
}, | ||
new() | ||
{ | ||
Name = "ProtoTest.Post", | ||
TableName = "Post", | ||
PrimaryKey = "Key: Post.PostId PK", | ||
Properties = | ||
{ | ||
"Property: Post.PostId (postId_, int) Required PK AfterSave:Throw ValueGenerated.OnAdd", | ||
"Property: Post.AuthorId (authorId_, int) Required FK Index", | ||
"Property: Post.DateCreated (dateCreated_, Timestamp)", | ||
"Property: Post.PostStat (postStat_, PostStatus) Required", | ||
"Property: Post.Title (title_, string)", | ||
}, | ||
Indexes = { "{'AuthorId'} ", }, | ||
FKs = { "ForeignKey: Post {'AuthorId'} -> Author {'AuthorId'} ToPrincipal: PostAuthor Cascade", }, | ||
Navigations = { "Navigation: Post.PostAuthor (postAuthor_, Author) ToPrincipal Author", }, | ||
SkipNavigations = | ||
{ | ||
"SkipNavigation: Post.TagsInPostData (tagsInPostData_, RepeatedField<Tag>) CollectionTag Inverse: PostsInTagData", | ||
}, | ||
}, | ||
new() | ||
{ | ||
Name = "ProtoTest.Tag", | ||
TableName = "Tag", | ||
PrimaryKey = "Key: Tag.TagId PK", | ||
Properties = | ||
{ | ||
"Property: Tag.TagId (tagId_, int) Required PK AfterSave:Throw ValueGenerated.OnAdd", | ||
"Property: Tag.Name (name_, string)", | ||
}, | ||
SkipNavigations = | ||
{ | ||
"SkipNavigation: Tag.PostsInTagData (postsInTagData_, RepeatedField<Post>) CollectionPost Inverse: TagsInPostData", | ||
}, | ||
}, | ||
}; | ||
|
||
[ConditionalFact] | ||
public void Can_build_Grpc_model() | ||
{ | ||
using var context = Fixture.CreateContext(); | ||
|
||
var entityTypeMappings = context.Model.GetEntityTypes().Select(e => new EntityTypeMapping(e)).ToList(); | ||
EntityTypeMapping.AssertEqual(ExpectedMappings, entityTypeMappings); | ||
} | ||
|
||
[ConditionalFact] | ||
public void Can_query_Grpc_model() | ||
{ | ||
using var context = Fixture.CreateContext(); | ||
|
||
var post = context.Set<Post>().Include(e => e.PostAuthor).Include(e => e.TagsInPostData).Single(); | ||
|
||
Assert.Equal("Arthur's post", post.Title); | ||
Assert.Equal(new DateTime(2021, 9, 3, 12, 10, 0, DateTimeKind.Utc), post.DateCreated.ToDateTime()); | ||
Assert.Equal(PostStatus.Published, post.PostStat); | ||
Assert.Equal("Arthur", post.PostAuthor.Name); | ||
Assert.Equal(new DateTime(1973, 9, 3, 12, 10, 0, DateTimeKind.Utc), post.PostAuthor.DateCreated.ToDateTime()); | ||
|
||
Assert.Equal(2, post.TagsInPostData.Count); | ||
Assert.Contains("Puppies", post.TagsInPostData.Select(e => e.Name).ToList()); | ||
Assert.Contains("Kittens", post.TagsInPostData.Select(e => e.Name).ToList()); | ||
Assert.Same(post, post.TagsInPostData.First().PostsInTagData.First()); | ||
Assert.Same(post, post.TagsInPostData.Skip(1).First().PostsInTagData.First()); | ||
} | ||
|
||
public class GrpcContext : PoolableDbContext | ||
{ | ||
public GrpcContext(DbContextOptions options) | ||
: base(options) | ||
{ | ||
} | ||
|
||
protected override void OnModelCreating(ModelBuilder modelBuilder) | ||
{ | ||
var timeStampConverter = new ValueConverter<Timestamp, DateTime>( | ||
v => v.ToDateTime(), | ||
v => new DateTime(v.Ticks, DateTimeKind.Utc).ToTimestamp()); | ||
|
||
modelBuilder.Entity<Author>().Property(e => e.DateCreated).HasConversion(timeStampConverter); | ||
modelBuilder.Entity<Post>().Property(e => e.DateCreated).HasConversion(timeStampConverter); | ||
modelBuilder.Entity<Tag>(); | ||
} | ||
} | ||
|
||
public abstract class GrpcFixtureBase : SharedStoreFixtureBase<GrpcContext> | ||
{ | ||
protected override string StoreName { get; } = "GrpcTest"; | ||
|
||
protected override void Seed(GrpcContext context) | ||
{ | ||
var post = new Post | ||
{ | ||
DateCreated = Timestamp.FromDateTime(new DateTime(2021, 9, 3, 12, 10, 0, DateTimeKind.Utc)), | ||
Title = "Arthur's post", | ||
PostAuthor = new Author | ||
{ | ||
DateCreated = Timestamp.FromDateTime(new DateTime(1973, 9, 3, 12, 10, 0, DateTimeKind.Utc)), Name = "Arthur" | ||
}, | ||
PostStat = PostStatus.Published, | ||
TagsInPostData = { new Tag { Name = "Kittens" }, new Tag { Name = "Puppies" } } | ||
}; | ||
|
||
context.Add(post); | ||
|
||
context.SaveChanges(); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
syntax = "proto3"; | ||
option csharp_namespace = "ProtoTest"; | ||
import "google/protobuf/empty.proto"; | ||
import "google/protobuf/timestamp.proto"; | ||
package Test; | ||
|
||
service ProtoTest{ | ||
rpc GetPosts(google.protobuf.Empty) returns (Posts); | ||
rpc GetPost(GetPostQuery) returns (Post); | ||
rpc GetAuthors(google.protobuf.Empty) returns (Authors); | ||
rpc GetAuthor(GetAuthorQuery) returns (Author); | ||
} | ||
|
||
message Author { | ||
int32 author_id = 1; | ||
string name = 2; | ||
google.protobuf.Timestamp date_created = 3; | ||
} | ||
message Authors { | ||
repeated Author authors_data = 1; | ||
} | ||
|
||
message Post { | ||
int32 post_id = 1; | ||
int32 author_id = 2; | ||
string title = 3; | ||
google.protobuf.Timestamp date_created = 4; | ||
PostStatus post_stat = 5; | ||
Author post_author = 6; | ||
repeated Tag tags_in_post_data = 7; | ||
} | ||
message Posts { | ||
repeated Post posts_data = 1; | ||
} | ||
|
||
message Tag { | ||
int32 tag_id = 1; | ||
string name = 2; | ||
repeated Post posts_in_tag_data = 3; | ||
} | ||
message Tags { | ||
repeated Tag tags_data = 1; | ||
} | ||
|
||
enum PostStatus { | ||
POST_STATUS_HIDDEN = 0; | ||
POST_STATUS_PUBLISHED = 1; | ||
POST_STATUS_DELETED = 2; | ||
} | ||
|
||
message GetPostQuery { | ||
int32 id = 1; | ||
} | ||
|
||
message GetAuthorQuery { | ||
int32 id = 1; | ||
} |
21 changes: 21 additions & 0 deletions
21
test/EFCore.AspNet.SqlServer.FunctionalTests/GrpcSqlServerTest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using Microsoft.EntityFrameworkCore.TestUtilities; | ||
|
||
namespace Microsoft.EntityFrameworkCore | ||
{ | ||
public class GrpcSqlServerTest : GrpcTestBase<GrpcSqlServerTest.GrpcSqlServerFixture> | ||
{ | ||
public GrpcSqlServerTest(GrpcSqlServerFixture fixture) | ||
: base(fixture) | ||
{ | ||
} | ||
|
||
public class GrpcSqlServerFixture : GrpcFixtureBase | ||
{ | ||
protected override ITestStoreFactory TestStoreFactory | ||
=> SqlServerTestStoreFactory.Instance; | ||
} | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
test/EFCore.AspNet.Sqlite.FunctionalTests/GrpcSqliteTest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using Microsoft.EntityFrameworkCore.TestUtilities; | ||
|
||
namespace Microsoft.EntityFrameworkCore | ||
{ | ||
public class GrpcSqliteTest : GrpcTestBase<GrpcSqliteTest.GrpcSqliteFixture> | ||
{ | ||
public GrpcSqliteTest(GrpcSqliteFixture fixture) | ||
: base(fixture) | ||
{ | ||
} | ||
|
||
public class GrpcSqliteFixture : GrpcFixtureBase | ||
{ | ||
protected override ITestStoreFactory TestStoreFactory | ||
=> SqliteTestStoreFactory.Instance; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters