Skip to content

Commit 9667f74

Browse files
committed
Merge in 'release/5.0' changes
2 parents be980db + 0e28884 commit 9667f74

9 files changed

Lines changed: 333 additions & 21 deletions

File tree

src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -841,13 +841,14 @@ protected virtual void GenerateEntityTypeAnnotations(
841841
|| entityType.BaseType == null)
842842
{
843843
var tableName = (string)tableNameAnnotation?.Value ?? entityType.GetTableName();
844-
if (tableName != null)
844+
if (tableName != null
845+
|| tableNameAnnotation != null)
845846
{
846847
stringBuilder
847848
.AppendLine()
848849
.Append(builderName)
849850
.Append(".ToTable(")
850-
.Append(Code.Literal(tableName));
851+
.Append(Code.UnknownLiteral(tableName));
851852
if (tableNameAnnotation != null)
852853
{
853854
annotations.Remove(tableNameAnnotation.Name);

src/EFCore.Design/Migrations/Design/MigrationsCodeGenerator.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ private static IEnumerable<IAnnotatable> GetAnnotatables(IModel model)
216216
private IEnumerable<string> GetAnnotationNamespaces(IEnumerable<IAnnotatable> items)
217217
=> items.SelectMany(
218218
i => Dependencies.AnnotationCodeGenerator.FilterIgnoredAnnotations(i.GetAnnotations())
219+
.Where(a => a.Value != null)
219220
.Select(a => new { Annotatable = i, Annotation = a })
220221
.SelectMany(a => GetProviderType(a.Annotatable, a.Annotation.Value.GetType()).GetNamespaces()));
221222

src/EFCore.Design/Scaffolding/Internal/CSharpEntityTypeGenerator.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ protected virtual void GenerateEntityTypeDataAnnotations([NotNull] IEntityType e
151151
{
152152
attributeWriter.AddParameter(_code.UnknownLiteral(argument));
153153
}
154+
155+
_sb.AppendLine(attributeWriter.ToString());
154156
}
155157
}
156158

@@ -300,6 +302,8 @@ protected virtual void GeneratePropertyDataAnnotations([NotNull] IProperty prope
300302
{
301303
attributeWriter.AddParameter(_code.UnknownLiteral(argument));
302304
}
305+
306+
_sb.AppendLine(attributeWriter.ToString());
303307
}
304308
}
305309

src/EFCore.Relational/Design/AnnotationCodeGenerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public AnnotationCodeGenerator([NotNull] AnnotationCodeGeneratorDependencies dep
6969
public virtual IEnumerable<IAnnotation> FilterIgnoredAnnotations(IEnumerable<IAnnotation> annotations)
7070
=> annotations.Where(
7171
a => !(
72-
a.Value is null
72+
(a.Value is null && a.Name != RelationalAnnotationNames.TableName)
7373
|| CoreAnnotationNames.AllNames.Contains(a.Name)
7474
|| _ignoredRelationalAnnotations.Contains(a.Name)));
7575

src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,7 @@ public static string SetFunctionName(
544544
[CanBeNull] string name,
545545
bool fromDataAnnotation = false)
546546
=> (string)entityType.SetAnnotation(
547-
RelationalAnnotationNames.ViewName,
547+
RelationalAnnotationNames.FunctionName,
548548
Check.NullButNotEmpty(name, nameof(name)),
549549
fromDataAnnotation)?.Value;
550550

test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -526,9 +526,7 @@ private static IQueryable<TestKeylessType> GetCountByYear(int id)
526526
=> throw new NotImplementedException();
527527

528528
[ConditionalFact]
529-
public void TVF_types_are_stored_in_the_model_snapshot()
530-
{
531-
Test(
529+
public void TVF_types_are_stored_in_the_model_snapshot() => Test(
532530
builder =>
533531
{
534532
builder.HasDbFunction(
@@ -545,9 +543,15 @@ public void TVF_types_are_stored_in_the_model_snapshot()
545543
{
546544
b.Property<string>(""Something"")
547545
.HasColumnType(""nvarchar(max)"");
546+
547+
b.ToTable(null);
548548
});"),
549-
o => Assert.Null(o.GetEntityTypes().Single().GetFunctionName()));
550-
}
549+
o =>
550+
{
551+
var entityType = o.GetEntityTypes().Single();
552+
Assert.Null(entityType.GetFunctionName());
553+
Assert.Null(entityType.GetTableName());
554+
});
551555

552556
[ConditionalFact]
553557
public void Entity_types_mapped_to_functions_are_stored_in_the_model_snapshot()

test/EFCore.Design.Tests/Scaffolding/Internal/CSharpEntityTypeGeneratorTest.cs

Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using System;
5+
using System.Collections.Generic;
46
using System.Linq;
7+
using Microsoft.EntityFrameworkCore.Design;
8+
using Microsoft.EntityFrameworkCore.Infrastructure;
59
using Microsoft.EntityFrameworkCore.Internal;
10+
using Microsoft.EntityFrameworkCore.Metadata;
11+
using Microsoft.EntityFrameworkCore.SqlServer.Design.Internal;
12+
using Microsoft.EntityFrameworkCore.SqlServer.Metadata.Internal;
13+
using Microsoft.Extensions.DependencyInjection;
14+
using Microsoft.Extensions.DependencyInjection.Extensions;
615
using Xunit;
716

817
namespace Microsoft.EntityFrameworkCore.Scaffolding.Internal
@@ -1402,5 +1411,277 @@ public partial class Post
14021411
Assert.Equal("OriginalPosts", originalInverseNavigation.Name);
14031412
});
14041413
}
1414+
1415+
[ConditionalFact]
1416+
public void Entity_with_custom_annotation()
1417+
{
1418+
Test(
1419+
modelBuilder => modelBuilder
1420+
.Entity(
1421+
"EntityWithAnnotation",
1422+
x =>
1423+
{
1424+
x.HasAnnotation("Custom:EntityAnnotation", "first argument");
1425+
x.Property<int>("Id");
1426+
x.HasKey("Id");
1427+
}),
1428+
new ModelCodeGenerationOptions { UseDataAnnotations = true },
1429+
code =>
1430+
{
1431+
AssertFileContents(
1432+
@"using System;
1433+
using System.Collections.Generic;
1434+
using System.ComponentModel.DataAnnotations;
1435+
using System.ComponentModel.DataAnnotations.Schema;
1436+
using Microsoft.EntityFrameworkCore;
1437+
1438+
#nullable disable
1439+
1440+
namespace TestNamespace
1441+
{
1442+
[CustomEntityDataAnnotation(""first argument"")]
1443+
public partial class EntityWithAnnotation
1444+
{
1445+
[Key]
1446+
public int Id { get; set; }
1447+
}
1448+
}
1449+
",
1450+
code.AdditionalFiles.Single(f => f.Path == "EntityWithAnnotation.cs"));
1451+
1452+
AssertFileContents(
1453+
@"using System;
1454+
using Microsoft.EntityFrameworkCore;
1455+
using Microsoft.EntityFrameworkCore.Metadata;
1456+
1457+
#nullable disable
1458+
1459+
namespace TestNamespace
1460+
{
1461+
public partial class TestDbContext : DbContext
1462+
{
1463+
public TestDbContext()
1464+
{
1465+
}
1466+
1467+
public TestDbContext(DbContextOptions<TestDbContext> options)
1468+
: base(options)
1469+
{
1470+
}
1471+
1472+
public virtual DbSet<EntityWithAnnotation> EntityWithAnnotation { get; set; }
1473+
1474+
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
1475+
{
1476+
if (!optionsBuilder.IsConfigured)
1477+
{
1478+
#warning "
1479+
+ DesignStrings.SensitiveInformationWarning
1480+
+ @"
1481+
optionsBuilder.UseSqlServer(""Initial Catalog=TestDatabase"");
1482+
}
1483+
}
1484+
1485+
protected override void OnModelCreating(ModelBuilder modelBuilder)
1486+
{
1487+
modelBuilder.Entity<EntityWithAnnotation>(entity =>
1488+
{
1489+
entity.Property(e => e.Id).UseIdentityColumn();
1490+
});
1491+
1492+
OnModelCreatingPartial(modelBuilder);
1493+
}
1494+
1495+
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
1496+
}
1497+
}
1498+
",
1499+
code.ContextFile);
1500+
},
1501+
assertModel: null,
1502+
skipBuild: true);
1503+
}
1504+
1505+
[ConditionalFact]
1506+
public void Entity_property_with_custom_annotation()
1507+
{
1508+
Test(
1509+
modelBuilder => modelBuilder
1510+
.Entity(
1511+
"EntityWithPropertyAnnotation",
1512+
x =>
1513+
{
1514+
x.Property<int>("Id")
1515+
.HasAnnotation("Custom:PropertyAnnotation", "first argument");
1516+
x.HasKey("Id");
1517+
}),
1518+
new ModelCodeGenerationOptions { UseDataAnnotations = true },
1519+
code =>
1520+
{
1521+
AssertFileContents(
1522+
@"using System;
1523+
using System.Collections.Generic;
1524+
using System.ComponentModel.DataAnnotations;
1525+
using System.ComponentModel.DataAnnotations.Schema;
1526+
using Microsoft.EntityFrameworkCore;
1527+
1528+
#nullable disable
1529+
1530+
namespace TestNamespace
1531+
{
1532+
public partial class EntityWithPropertyAnnotation
1533+
{
1534+
[Key]
1535+
[CustomPropertyDataAnnotation(""first argument"")]
1536+
public int Id { get; set; }
1537+
}
1538+
}
1539+
",
1540+
code.AdditionalFiles.Single(f => f.Path == "EntityWithPropertyAnnotation.cs"));
1541+
1542+
AssertFileContents(
1543+
@"using System;
1544+
using Microsoft.EntityFrameworkCore;
1545+
using Microsoft.EntityFrameworkCore.Metadata;
1546+
1547+
#nullable disable
1548+
1549+
namespace TestNamespace
1550+
{
1551+
public partial class TestDbContext : DbContext
1552+
{
1553+
public TestDbContext()
1554+
{
1555+
}
1556+
1557+
public TestDbContext(DbContextOptions<TestDbContext> options)
1558+
: base(options)
1559+
{
1560+
}
1561+
1562+
public virtual DbSet<EntityWithPropertyAnnotation> EntityWithPropertyAnnotation { get; set; }
1563+
1564+
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
1565+
{
1566+
if (!optionsBuilder.IsConfigured)
1567+
{
1568+
#warning "
1569+
+ DesignStrings.SensitiveInformationWarning
1570+
+ @"
1571+
optionsBuilder.UseSqlServer(""Initial Catalog=TestDatabase"");
1572+
}
1573+
}
1574+
1575+
protected override void OnModelCreating(ModelBuilder modelBuilder)
1576+
{
1577+
modelBuilder.Entity<EntityWithPropertyAnnotation>(entity =>
1578+
{
1579+
entity.Property(e => e.Id).UseIdentityColumn();
1580+
});
1581+
1582+
OnModelCreatingPartial(modelBuilder);
1583+
}
1584+
1585+
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
1586+
}
1587+
}
1588+
",
1589+
code.ContextFile);
1590+
},
1591+
assertModel: null,
1592+
skipBuild: true);
1593+
}
1594+
1595+
protected override void AddModelServices(IServiceCollection services)
1596+
{
1597+
services.Replace(ServiceDescriptor.Singleton<IRelationalAnnotationProvider, ModelAnnotationProvider>());
1598+
}
1599+
1600+
protected override void AddScaffoldingServices(IServiceCollection services)
1601+
{
1602+
services.Replace(ServiceDescriptor.Singleton<IAnnotationCodeGenerator, ModelAnnotationCodeGenerator>());
1603+
}
1604+
1605+
public class ModelAnnotationProvider : SqlServerAnnotationProvider
1606+
{
1607+
public ModelAnnotationProvider(RelationalAnnotationProviderDependencies dependencies)
1608+
: base(dependencies)
1609+
{
1610+
}
1611+
1612+
/// <inheritdoc />
1613+
public override IEnumerable<IAnnotation> For(ITable table)
1614+
{
1615+
foreach (var annotation in base.For(table))
1616+
{
1617+
yield return annotation;
1618+
}
1619+
1620+
var entityType = table.EntityTypeMappings.First().EntityType;
1621+
1622+
foreach (var annotation in entityType.GetAnnotations().Where(a => a.Name == "Custom:EntityAnnotation"))
1623+
{
1624+
yield return annotation;
1625+
}
1626+
}
1627+
1628+
/// <inheritdoc />
1629+
public override IEnumerable<IAnnotation> For(IColumn column)
1630+
{
1631+
foreach (var annotation in base.For(column))
1632+
{
1633+
yield return annotation;
1634+
}
1635+
1636+
var properties = column.PropertyMappings.Select(m => m.Property);
1637+
var annotations = properties.SelectMany(p => p.GetAnnotations()).GroupBy(a => a.Name).Select(g => g.First());
1638+
1639+
foreach (var annotation in annotations.Where(a => a.Name == "Custom:PropertyAnnotation"))
1640+
{
1641+
yield return annotation;
1642+
}
1643+
}
1644+
}
1645+
1646+
public class ModelAnnotationCodeGenerator : SqlServerAnnotationCodeGenerator
1647+
{
1648+
public ModelAnnotationCodeGenerator(AnnotationCodeGeneratorDependencies dependencies)
1649+
: base(dependencies)
1650+
{
1651+
}
1652+
1653+
protected override AttributeCodeFragment GenerateDataAnnotation(IEntityType entityType, IAnnotation annotation)
1654+
=> annotation.Name switch
1655+
{
1656+
"Custom:EntityAnnotation" => new AttributeCodeFragment(
1657+
typeof(CustomEntityDataAnnotationAttribute), new object[] { annotation.Value as string }),
1658+
_ => base.GenerateDataAnnotation(entityType, annotation)
1659+
};
1660+
1661+
protected override AttributeCodeFragment GenerateDataAnnotation(IProperty property, IAnnotation annotation)
1662+
=> annotation.Name switch
1663+
{
1664+
"Custom:PropertyAnnotation" => new AttributeCodeFragment(typeof(CustomPropertyDataAnnotationAttribute), new object[] {annotation.Value as string}),
1665+
_ => base.GenerateDataAnnotation(property, annotation)
1666+
};
1667+
}
1668+
1669+
[AttributeUsage(AttributeTargets.Class)]
1670+
public class CustomEntityDataAnnotationAttribute : Attribute
1671+
{
1672+
public CustomEntityDataAnnotationAttribute(string argument)
1673+
=> Argument = argument;
1674+
1675+
public virtual string Argument { get; }
1676+
}
1677+
1678+
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
1679+
public class CustomPropertyDataAnnotationAttribute : Attribute
1680+
{
1681+
public CustomPropertyDataAnnotationAttribute(string argument)
1682+
=> Argument = argument;
1683+
1684+
public virtual string Argument { get; }
1685+
}
14051686
}
14061687
}

0 commit comments

Comments
 (0)