diff --git a/Changelog.md b/Changelog.md index a7b54fc33..29a4ba834 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,20 @@ +# 5.4.4 / EF Core 3.1.0 + +### EF Core 3.1.0 +* Initial support for Owned Entities for one-to-one navigation properties (#500) + * Owned entities without explicit keys are mapped to OpenRiaServices's [Complex Types] + * Owned entities with explicit keys are generated as normal *"Entities"* but are automatically annotated with `[Composition]` + * EFCore "Complex Types" introduced in EFCore 8.0 does not have any special handling +* Add new helper method `AttachAsModified(TEntity entity)` (#506) + * It works similar to the existing `AttachAsModified` extension methods on `DbSet` but + * is smarter (works with and without original entity) + * reduces code that needs to be written and works both with and without "OriginalEntity" (`RoundTripAttribute`) +* Add package README to `OpenRiaServices.Server.EntityFrameworkCore` + +### Code generation +* Log whole Exceptions in DomainServiceCatalog instead of just message (#502), for better error messages on code generation failure +* Call "dotnet CodeGenTask.dll" instead of "CodeGenTask.exe" #503 + # EF Core 3.0.0 * Target EF Core 8 diff --git a/src/FeaturePackage.targets b/src/FeaturePackage.targets deleted file mode 100644 index 3da8e7ec2..000000000 --- a/src/FeaturePackage.targets +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - $(ProgramFiles)\Reference Assemblies\Microsoft\Framework\Silverlight\v5.0 - $(ProgramFiles)\Microsoft SDKs\Silverlight\v5.0\Libraries\Client - - true - false - true - $(MSBuildThisFileDirectory)\snk\OpenRiaServices.snk - $(MSBuildThisFileDirectory)\snk\Tests.snk - - - - - true - full - false - - - - pdbonly - true - - - - - . - - - \ No newline at end of file diff --git a/src/OpenRiaServices.Server.EntityFrameworkCore/Framework/EFCoreDescriptionProvider.cs b/src/OpenRiaServices.Server.EntityFrameworkCore/Framework/EFCoreDescriptionProvider.cs index 5fb3fd14b..aeccc118e 100644 --- a/src/OpenRiaServices.Server.EntityFrameworkCore/Framework/EFCoreDescriptionProvider.cs +++ b/src/OpenRiaServices.Server.EntityFrameworkCore/Framework/EFCoreDescriptionProvider.cs @@ -49,6 +49,9 @@ public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, ICustom td = new EFCoreTypeDescriptor(_typeDescriptionContext, entityType, parent); } #else + // TODO: Determine if we can handle Complex Types + // - it must "look the same" for all usages (be configured the same in all places to make sense) + // - Should they instead be treated as different types per usage (on the client) if (model != null && model.FindEntityType(objectType.FullName) is IReadOnlyEntityType entityType) { td = new EFCoreTypeDescriptor(_typeDescriptionContext, entityType, parent); diff --git a/src/OpenRiaServices.Server.EntityFrameworkCore/Framework/EFCoreTypeDescriptionContext.cs b/src/OpenRiaServices.Server.EntityFrameworkCore/Framework/EFCoreTypeDescriptionContext.cs index 21c687480..a91bcec9b 100644 --- a/src/OpenRiaServices.Server.EntityFrameworkCore/Framework/EFCoreTypeDescriptionContext.cs +++ b/src/OpenRiaServices.Server.EntityFrameworkCore/Framework/EFCoreTypeDescriptionContext.cs @@ -7,6 +7,12 @@ using Microsoft.EntityFrameworkCore; using System.Diagnostics; +#if NETSTANDARD +using IReadOnlyNavigation = Microsoft.EntityFrameworkCore.Metadata.INavigation; +using IReadOnlyEntityType = Microsoft.EntityFrameworkCore.Metadata.IEntityType; +using IReadOnlyProperty = Microsoft.EntityFrameworkCore.Metadata.IProperty; +#endif + namespace OpenRiaServices.Server.EntityFrameworkCore { /// @@ -45,23 +51,21 @@ public IModel Model } // Verify that full name is not null since Model.FindEntityType throws argument exception if full name is null -#if NETSTANDARD2_0 - public IEntityType GetEntityType(Type type) => type?.FullName != null ? Model.FindEntityType(type) : null; -#else - public IReadOnlyEntityType GetEntityType(Type type) => type?.FullName != null ? ((IReadOnlyModel)Model).FindEntityType(type) : null; -#endif + public IReadOnlyEntityType GetEntityType(Type type) => type?.FullName != null ? Model.FindEntityType(type) : null; /// /// Creates an AssociationAttribute for the specified navigation property /// /// The navigation property that corresponds to the association (it identifies the end points) /// A new AssociationAttribute that describes the given navigation property association - internal AssociationAttribute CreateAssociationAttribute(INavigation navigationProperty) + internal static AssociationAttribute CreateAssociationAttribute(IReadOnlyNavigation navigationProperty) { var fk = navigationProperty.ForeignKey; string thisKey; string otherKey; + string name = fk.GetConstraintName(); + #if NETSTANDARD2_0 if (navigationProperty.IsDependentToPrincipal()) #else @@ -77,17 +81,26 @@ internal AssociationAttribute CreateAssociationAttribute(INavigation navigationP thisKey = FormatMemberList(fk.PrincipalKey.Properties); otherKey = FormatMemberList(fk.Properties); + Debug.Assert(fk.IsOwnership == fk.DeclaringEntityType.IsOwned()); + + // In case there are multiple navigation properties to Owned entities + // and they have explicity defined keys (they mirror the owners key) then + // they will have the same foreign key name and we have to make them unique + if (fk.DeclaringEntityType.IsOwned()) + { + name += "|owns:" + navigationProperty.Name; + } } - var assocAttrib = new AssociationAttribute(fk.GetConstraintName(), thisKey, otherKey); + var assocAttrib = new AssociationAttribute(name, thisKey, otherKey); assocAttrib.IsForeignKey = IsForeignKey(navigationProperty); return assocAttrib; } #if NETSTANDARD2_0 - private static bool IsForeignKey(INavigation navigationProperty) => navigationProperty.IsDependentToPrincipal(); + private static bool IsForeignKey(IReadOnlyNavigation navigationProperty) => navigationProperty.IsDependentToPrincipal(); #else - private static bool IsForeignKey(INavigation navigationProperty) => navigationProperty.IsOnDependent; + private static bool IsForeignKey(IReadOnlyNavigation navigationProperty) => navigationProperty.IsOnDependent; #endif @@ -96,7 +109,7 @@ internal AssociationAttribute CreateAssociationAttribute(INavigation navigationP /// /// A collection of members. /// A comma delimited list of member names. - protected static string FormatMemberList(IEnumerable members) + protected static string FormatMemberList(IEnumerable members) { string memberList = string.Empty; foreach (var prop in members) diff --git a/src/OpenRiaServices.Server.EntityFrameworkCore/Framework/EFCoreTypeDescriptor.cs b/src/OpenRiaServices.Server.EntityFrameworkCore/Framework/EFCoreTypeDescriptor.cs index 9897a89df..23d208796 100644 --- a/src/OpenRiaServices.Server.EntityFrameworkCore/Framework/EFCoreTypeDescriptor.cs +++ b/src/OpenRiaServices.Server.EntityFrameworkCore/Framework/EFCoreTypeDescriptor.cs @@ -117,12 +117,10 @@ protected override IEnumerable GetMemberAttributes(PropertyDescriptor bool hasKeyAttribute = pd.Attributes[typeof(KeyAttribute)] != null; var property = _entityType.FindProperty(pd.Name); - // TODO: Review all usage of isEntity to validate if we should really copy logic from EF6 - bool isEntity = !_entityType.IsOwned(); if (property != null) { - if (isEntity && property.IsPrimaryKey() && !hasKeyAttribute) + if (property.IsPrimaryKey() && !hasKeyAttribute) { attributes.Add(new KeyAttribute()); hasKeyAttribute = true; @@ -192,7 +190,7 @@ protected override IEnumerable GetMemberAttributes(PropertyDescriptor bool isStringType = pd.PropertyType == typeof(string) || pd.PropertyType == typeof(char[]); if (isStringType && pd.Attributes[typeof(StringLengthAttribute)] == null && - property.GetMaxLength() is int maxLength) + property.GetMaxLength() is int maxLength) { attributes.Add(new StringLengthAttribute(maxLength)); } @@ -228,33 +226,39 @@ protected override IEnumerable GetMemberAttributes(PropertyDescriptor attributes.Add(new RoundtripOriginalAttribute()); } } - } - // Add the Editable attribute if required - if (editableAttribute != null && pd.Attributes[typeof(EditableAttribute)] == null) - { - attributes.Add(editableAttribute); + // Add the Editable attribute if required + if (editableAttribute != null && pd.Attributes[typeof(EditableAttribute)] == null) + { + attributes.Add(editableAttribute); + } } // Add AssociationAttribute if required for the specified property - if (isEntity - && _entityType.FindNavigation(pd.Name) is INavigation navigation) + if (_entityType.FindNavigation(pd.Name) is { } navigation) { #if NETSTANDARD2_0 bool isManyToMany = navigation.IsCollection() && navigation.FindInverse()?.IsCollection() == true; + bool addAssociationAttribute = !isManyToMany; #else bool isManyToMany = navigation.IsCollection && navigation.Inverse?.IsCollection == true; + bool addAssociationAttribute = !isManyToMany + // Don't generate association attributes for Owned types (onless they have all FK fields explictly defined, in which case they can be treated as Entities) + // if we generate association attributes then it cannot be treated as a ComplexObject + && !(navigation.ForeignKey.Properties.Any(static p => p.IsShadowProperty())); #endif - if (!isManyToMany) + + if (addAssociationAttribute) { - var assocAttrib = (AssociationAttribute)pd.Attributes[typeof(AssociationAttribute)]; - if (assocAttrib == null) + if (pd.Attributes[typeof(AssociationAttribute)] is null) + attributes.Add(EFCoreTypeDescriptionContext.CreateAssociationAttribute(navigation)); +#if NET + if (navigation.TargetEntityType.IsOwned() && pd.Attributes[typeof(CompositionAttribute)] is null) { - assocAttrib = TypeDescriptionContext.CreateAssociationAttribute(navigation); - attributes.Add(assocAttrib); + attributes.Add(new CompositionAttribute()); } +#endif } - } return attributes.ToArray(); diff --git a/src/OpenRiaServices.Server.EntityFrameworkCore/Framework/OpenRiaServices.Server.EntityFrameworkCore.csproj b/src/OpenRiaServices.Server.EntityFrameworkCore/Framework/OpenRiaServices.Server.EntityFrameworkCore.csproj index f54db3bb0..e04404e4c 100644 --- a/src/OpenRiaServices.Server.EntityFrameworkCore/Framework/OpenRiaServices.Server.EntityFrameworkCore.csproj +++ b/src/OpenRiaServices.Server.EntityFrameworkCore/Framework/OpenRiaServices.Server.EntityFrameworkCore.csproj @@ -3,10 +3,11 @@ net8.0;net6.0;netstandard2.0 $(DefineConstants);SERVERFX;EFCORE true - 3.0.0 + 3.1.0 3.0.0 true + README.md LICENSE.md @@ -41,6 +42,7 @@ + diff --git a/src/OpenRiaServices.Server.EntityFrameworkCore/Framework/README.md b/src/OpenRiaServices.Server.EntityFrameworkCore/Framework/README.md new file mode 100644 index 000000000..d9e3c6225 --- /dev/null +++ b/src/OpenRiaServices.Server.EntityFrameworkCore/Framework/README.md @@ -0,0 +1,83 @@ +[![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://vshymanskyy.github.io/StandWithUkraine) + + +## TERM OF USE + +By using this project or its source code, for any purpose and in any shape or form, you grant your **agreement** to all the following statements: + +- You **condemn Russia and its military aggression against Ukraine** +- You **recognize that Russia is an occupant that unlawfully invaded a sovereign state** +- You **support Ukraine's territorial integrity, including its claims over temporarily occupied territories of Crimea and Donbas** +- You **do not support the Russian invasion or contribute to its propaganda'** + +This excludes usage by the Russian state, Russian state-owned companies, Russian education who spread propaganda instead of truth, anyone who work with the *filtration camps*, or finance the war by importing Russian oil or gas. + +- You allow anonymized telemetry to collected and sent during the preview releases to gather feedback about usage + + + +## Getting Started + +1. Ensure you have setup and configured `OpenRiaServices.Hosting.AspNetCore` +2. Add a reference to *OpenRiaServices.Server.EntityFrameworkCore* + `dotnet add package OpenRiaServices.Server.EntityFrameworkCore` +3. Add one or more domainservices. +Given that you have a Ef Core model named `MyDbContext` with an entity `MyEntity` you add CRUD methods using something similar to below + +```csharp +using using Microsoft.EntityFrameworkCore; +using OpenRiaServices.Server.EntityFrameworkCore; + +[EnableClientAccess] +public class MyDomainService : DbDomainService +{ + // Not required: But it is generally a good idea to allow dependency injection of DbContext + public MyDomainService(MyDbContext dbContext) + : base(context) + { } + + /* Example of CUD methods */ + public void InsertMyEntity(MyEntity entity) + => DbContext.Entry(entity).State = EntityState.Added; // Or DbContext.Add, but it might add related entities differently + + public void UpdateMyEntity(MyEntity entity) + => base.AttachAsModified(entity); // This sets state to Modified and set modified status on individual properties based on client changes and if `RountTripOriginal` attribute is specified or not + + public void DeleteMyEntity(MyEntity entity) + => DbContext.Entry(entity).State = EntityState.Deleted; + + /* Query: + * Return IQueryable<> to automatically allow the client to add filtering, paging etc. + * The queries are performed async for best performance + */ + [Query] + IQueryable GetMyEntities() + => DbContext.MyEntities.OrderBy(x => x.Id); // Sort by id to get stable Skip/Take if client does paging +} +``` +4. Ensure that `MyDomainService` is mapped, (See [Setup instructions in OpenRiaServices.Hosting.AspNetCore readme](https://www.nuget.org/packages/OpenRiaServices.Hosting.AspNetCore)) + + +## Owned Entities + +* *one-to-one* relations using Owned Entities are fully supported + * Any EF Core configuration/metadata applied to the owned entity (such as Required, MaxLength etc) are part of generated client Code +* *one-to-many* relations might work, but it has not been verified at the moment + +### Owned Entities without explicit key +EF Core owned entities are mapped to OpenRiaServices's [Complex Types](https://openriaservices.gitbook.io/openriaservices/ee707348/ee707356/gg602753) as long as the owned entity does not have have an explicit key. + + +### Owned Entities with explicit key +If an explicit key to an owned entity then they are mapped as a normal entity and the navigation property to the owned entity adds `[Composition]` + +This makes the owned entity available during Insert, Update and Delete operations and prevents if from accidentaly having all fields set to `null`. + +## Complex Types + +The *Complex Types* introduced in EF Core 8 are *partially supported** with some limitations. + +1. The types are mapped to to OpenRiaServices's [Complex Types] +2. Any ef core configuration/metadata applied to the ComplexType (as part of fluent configuration) **IS NOT** discovered. +The `DbDomainServiceDescriptionProvider` and `DbDomainService` classes does not have any special handling of *Complex Types*. + * Attributes on the types are discovered as expected using the normal built in reflection based attribute discovery diff --git a/src/OpenRiaServices.Server.EntityFrameworkCore/Test/DbContextModel/Scenarios/ComplexTypes.cs b/src/OpenRiaServices.Server.EntityFrameworkCore/Test/DbContextModel/Scenarios/ComplexTypes.cs new file mode 100644 index 000000000..1ee85258c --- /dev/null +++ b/src/OpenRiaServices.Server.EntityFrameworkCore/Test/DbContextModel/Scenarios/ComplexTypes.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Text; +using Microsoft.EntityFrameworkCore; + +#nullable enable + +#if NET8_0_OR_GREATER + +namespace EFCoreModels.Scenarios.ComplexTypes +{ + + public class Address + { + public required string AddressLine { get; set; } + public required string City { get; set; } + } + + public class ContactInfo + { + public required Address Address { get; set; } + + public required string HomePhone { get; set; } + + public int PossibleId { get; set; } + } + + public class Employee + { + public int EmployeeId { get; set; } + public required ContactInfo ContactInfo { get; set; } + } + + public class ComplexTypesDbContext : DbContext + { + public ComplexTypesDbContext() + { + } + + public ComplexTypesDbContext(DbContextOptions options) + : base(options) + { + } + + public DbSet Employees { get; set; } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .ComplexProperty(typeof(ContactInfo), nameof(Employee.ContactInfo), x => + { + x.Property(nameof(ContactInfo.HomePhone)).HasMaxLength(24); + x.ComplexProperty(typeof(Address), nameof(ContactInfo.Address), address => + { + address.Property(nameof(Address.AddressLine)).HasMaxLength(100); + address.Property(nameof(Address.City)).HasMaxLength(50); + }); + }) + .HasKey(e => e.EmployeeId); + + base.OnModelCreating(modelBuilder); + } + + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + if (!optionsBuilder.IsConfigured) + { + optionsBuilder.UseSqlServer("Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=AdventureWorks;Integrated Security=True;MultipleActiveResultSets=True"); + } + } + } +} +#endif diff --git a/src/OpenRiaServices.Server.EntityFrameworkCore/Test/DbContextModel/Scenarios/OwnedTypes.cs b/src/OpenRiaServices.Server.EntityFrameworkCore/Test/DbContextModel/Scenarios/OwnedTypes.cs new file mode 100644 index 000000000..44fba90fc --- /dev/null +++ b/src/OpenRiaServices.Server.EntityFrameworkCore/Test/DbContextModel/Scenarios/OwnedTypes.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Text; +using Microsoft.EntityFrameworkCore; +using OpenRiaServices.Server; + +#nullable enable + +#if NETSTANDARD2_0 +namespace System.Runtime.CompilerServices +{ + internal class RequiredMemberAttribute { }; + internal class CompilerFeatureRequiredAttribute { + public CompilerFeatureRequiredAttribute() { } + public CompilerFeatureRequiredAttribute(string _) :this() { } + }; +} +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#endif + +namespace EFCoreModels.Scenarios.OwnedTypes +{ + + public class Address + { + public required string AddressLine { get; set; } + public required string City { get; set; } + } + + public class ContactInfo + { + public required Address Address { get; set; } + + public required string HomePhone { get; set; } + } + + public class OwnedEntityWithExplicitId + { + public int EmployeeId { get; set; } + public required string Description { get; set; } + } + + public class OwnedEntityWithBackNavigation + { + public required string Description { get; set; } + [Include] + public required Employee Employee { get; set; } + } + + public class OwnedEntityWithExplicitIdAndBackNavigation + { + public int EmployeeId { get; set; } + [Include] + public required Employee Employee { get; set; } + public required string Description { get; set; } + } + + public class Employee + { + public int EmployeeId { get; set; } + public required ContactInfo ContactInfo { get; set; } + [Include] + public required OwnedEntityWithExplicitId OwnedEntityWithExplicitId { get; set; } + [Include] + public required OwnedEntityWithExplicitIdAndBackNavigation OwnedEntityWithExplicitIdAndBackNavigation { get; set; } + public required OwnedEntityWithBackNavigation OwnedEntityWithBackNavigation { get; set; } + } + + // TODO: Owned typed with "backwards" FK + public class OwnedTypesDbContext : DbContext + { + public OwnedTypesDbContext() + { + } + + public OwnedTypesDbContext(DbContextOptions options) + : base(options) + { + } + + public DbSet Employees { get; set; } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .OwnsOne(nameof(Employee.ContactInfo), x => + { + x.Property(nameof(ContactInfo.HomePhone)).HasMaxLength(24); + x.OwnsOne(typeof(Address), nameof(ContactInfo.Address), address => + { + address.Property(nameof(Address.AddressLine)).HasMaxLength(100); + address.Property(nameof(Address.City)).HasMaxLength(50); + }); + }) + .OwnsOne(nameof(Employee.OwnedEntityWithExplicitId), x => + { + x.WithOwner().HasForeignKey(nameof(OwnedEntityWithExplicitId.EmployeeId)); + }) + .OwnsOne(nameof(Employee.OwnedEntityWithExplicitIdAndBackNavigation), x => + { + x.WithOwner(nameof(OwnedEntityWithExplicitIdAndBackNavigation.Employee)); + }) + .OwnsOne(nameof(Employee.OwnedEntityWithBackNavigation), x => + { + x.WithOwner(nameof(OwnedEntityWithBackNavigation.Employee)); + //x.Navigation(nameof(OwnedEntityWithBackNavigation.Employee)) + // .UsePropertyAccessMode(PropertyAccessMode.Property); + }) + .HasKey(nameof(Employee.EmployeeId)); + +#if NET8_0 + modelBuilder.Entity() + .Navigation(x => x.ContactInfo) + .IsRequired(); +#endif + + base.OnModelCreating(modelBuilder); + } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + if (!optionsBuilder.IsConfigured) + { + optionsBuilder.UseSqlServer("Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=AdventureWorks;Integrated Security=True;MultipleActiveResultSets=True"); + } + } + } +} diff --git a/src/OpenRiaServices.Server.EntityFrameworkCore/Test/OpenRiaServices.Server.EntityFrameworkCore.Test/DomainServiceDescriptionTests.cs b/src/OpenRiaServices.Server.EntityFrameworkCore/Test/OpenRiaServices.Server.EntityFrameworkCore.Test/DomainServiceDescriptionTests.cs new file mode 100644 index 000000000..a7907cf11 --- /dev/null +++ b/src/OpenRiaServices.Server.EntityFrameworkCore/Test/OpenRiaServices.Server.EntityFrameworkCore.Test/DomainServiceDescriptionTests.cs @@ -0,0 +1,119 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using OwnedTypes = EFCoreModels.Scenarios.OwnedTypes; +using ComplexTypes = EFCoreModels.Scenarios.ComplexTypes; +using MSTest = Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace OpenRiaServices.Server.EntityFrameworkCore.Test +{ + [TestClass] + public class DomainServiceDescriptionTests + { + /// + /// Verify that the EF metadata provider is registered for mapped CTs, and that attribute are inferred properly + /// + [TestMethod] + public void ComplexType_EFCore_OwnedTypes() + { + DomainServiceDescription dsd = DomainServiceDescription.GetDescription(typeof(EFCoreOwnedTypesService)); + + CollectionAssert.AreEquivalent(new[] { + typeof(OwnedTypes.Address), + typeof(OwnedTypes.ContactInfo), + typeof(OwnedTypes.OwnedEntityWithBackNavigation), + }, dsd.ComplexTypes.ToList()); + + CollectionAssert.AreEquivalent(new[] { + typeof(OwnedTypes.Employee), + typeof(OwnedTypes.OwnedEntityWithExplicitId), + typeof(OwnedTypes.OwnedEntityWithExplicitIdAndBackNavigation) + }, dsd.EntityTypes.ToList()); + + var employee = TypeDescriptor.GetProperties(typeof(OwnedTypes.Employee)); + Assert.IsNotNull(employee[nameof(OwnedTypes.Employee.EmployeeId)]!.Attributes[typeof(KeyAttribute)]); + +#pragma warning disable CS0618 // Type or member is obsolete + Assert.IsNull(employee[nameof(OwnedTypes.Employee.ContactInfo)]!.Attributes[typeof(AssociationAttribute)]); + Assert.IsNull(employee[nameof(OwnedTypes.Employee.OwnedEntityWithBackNavigation)]!.Attributes[typeof(AssociationAttribute)]); + Assert.IsNotNull(employee[nameof(OwnedTypes.Employee.OwnedEntityWithExplicitId)]!.Attributes[typeof(AssociationAttribute)]); + Assert.IsNotNull(employee[nameof(OwnedTypes.Employee.OwnedEntityWithExplicitIdAndBackNavigation)]!.Attributes[typeof(AssociationAttribute)]); +#pragma warning restore CS0618 // Type or member is obsolete + + //var contactInfoProperty = employee[nameof(OwnedTypes.Employee.ContactInfo)]!; + //Assert.IsNotNull(contactInfoProperty.Attributes[typeof(RequiredAttribute)], "ComplexObject property should be required"); + + // the HomePhone member is mapped as non-nullable, with a max length of 24. Verify attributes + // were inferred + var contactInfo = TypeDescriptor.GetProperties(typeof(OwnedTypes.ContactInfo)); + var homePhone = contactInfo[nameof(OwnedTypes.ContactInfo.HomePhone)]!; + Assert.IsNotNull(homePhone.Attributes[typeof(RequiredAttribute)]); + StringLengthAttribute sl = (StringLengthAttribute)homePhone.Attributes[typeof(StringLengthAttribute)]!; + Assert.AreEqual(24, sl.MaximumLength); + //Assert.IsNotNull(contactInfo[nameof(OwnedTypes.ContactInfo.Address)]!.Attributes[typeof(RequiredAttribute)], "ComplexObject.ComplexObject property should be required"); + + // the AddressLine1 member is mapped as non-nullable, with a max length of 100. Verify attributes + // were inferred + var address = TypeDescriptor.GetProperties(typeof(OwnedTypes.Address)); + var addressLine = address[nameof(OwnedTypes.Address.AddressLine)]!; + Assert.IsNotNull(addressLine.Attributes[typeof(RequiredAttribute)]); + sl = (StringLengthAttribute)addressLine.Attributes[typeof(StringLengthAttribute)]!; + Assert.AreEqual(100, sl.MaximumLength); + } + + /// + /// Verify that the EF metadata provider is registered for mapped CTs, and that attribute are inferred properly + /// + [TestMethod] + [MSTest.Ignore("Does not work yet, attributes are not discovered on ComplexObjects")] + public void ComplexType_EFCore_ComplexTypes() + { + DomainServiceDescription dsd = DomainServiceDescription.GetDescription(typeof(EFCoreComplexTypesService)); + + CollectionAssert.AreEquivalent(dsd.EntityTypes.ToList(), new[] { typeof(ComplexTypes.Employee) }); + CollectionAssert.AreEquivalent(dsd.ComplexTypes.ToList(), new[] { typeof(ComplexTypes.Address), typeof(ComplexTypes.ContactInfo) }); + + var employee = TypeDescriptor.GetProperties(typeof(ComplexTypes.Employee)); + Assert.IsNotNull(employee[nameof(ComplexTypes.Employee.EmployeeId)]!.Attributes[typeof(KeyAttribute)]); + + //var contactInfoProperty = employee[nameof(OwnedTypes.Employee.ContactInfo)]!; + //Assert.IsNotNull(contactInfoProperty.Attributes[typeof(RequiredAttribute)], "ComplexObject property should be required"); + + // the HomePhone member is mapped as non-nullable, with a max length of 24. Verify attributes + // were inferred + var contactInfo = TypeDescriptor.GetProperties(typeof(ComplexTypes.ContactInfo)); + var homePhone = contactInfo[nameof(ComplexTypes.ContactInfo.HomePhone)]!; + + Assert.IsNotNull(homePhone.Attributes[typeof(RequiredAttribute)]); + StringLengthAttribute sl = (StringLengthAttribute)homePhone.Attributes[typeof(StringLengthAttribute)]!; + Assert.AreEqual(24, sl.MaximumLength); + //Assert.IsNotNull(contactInfo[nameof(OwnedTypes.ContactInfo.Address)]!.Attributes[typeof(RequiredAttribute)], "ComplexObject.ComplexObject property should be required"); + + + // the AddressLine1 member is mapped as non-nullable, with a max length of 100. Verify attributes + // were inferred + var address = TypeDescriptor.GetProperties(typeof(ComplexTypes.Address)); + var addressLine = address[nameof(ComplexTypes.Address.AddressLine)]!; + Assert.IsNotNull(addressLine.Attributes[typeof(RequiredAttribute)]); + sl = (StringLengthAttribute)addressLine.Attributes[typeof(StringLengthAttribute)]!; + Assert.AreEqual(100, sl.MaximumLength); + } + } + + [EnableClientAccess] + public class EFCoreOwnedTypesService : DbDomainService + { + public IQueryable GetCustomers() + { + return null!; + } + } + + [EnableClientAccess] + public class EFCoreComplexTypesService : DbDomainService + { + public IQueryable GetCustomers() + { + return null!; + } + } +} diff --git a/src/OpenRiaServices.Server.EntityFrameworkCore/Test/OpenRiaServices.Server.EntityFrameworkCore.Test/OpenRiaServices.Server.EntityFrameworkCore.Test.csproj b/src/OpenRiaServices.Server.EntityFrameworkCore/Test/OpenRiaServices.Server.EntityFrameworkCore.Test/OpenRiaServices.Server.EntityFrameworkCore.Test.csproj new file mode 100644 index 000000000..406ba3381 --- /dev/null +++ b/src/OpenRiaServices.Server.EntityFrameworkCore/Test/OpenRiaServices.Server.EntityFrameworkCore.Test/OpenRiaServices.Server.EntityFrameworkCore.Test.csproj @@ -0,0 +1,31 @@ + + + + net8.0 + enable + enable + + false + true + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + diff --git a/src/OpenRiaServices.Tools/Framework/DataContractProxyGenerator.cs b/src/OpenRiaServices.Tools/Framework/DataContractProxyGenerator.cs index 51c78d621..29b966137 100644 --- a/src/OpenRiaServices.Tools/Framework/DataContractProxyGenerator.cs +++ b/src/OpenRiaServices.Tools/Framework/DataContractProxyGenerator.cs @@ -385,8 +385,7 @@ protected virtual void GenerateProperty(PropertyDescriptor propertyDescriptor) property.Name = propertyName; property.Type = propTypeReference; property.Attributes = MemberAttributes.Public | MemberAttributes.Final; // final needed, else becomes virtual - var propertyAttributes = propertyDescriptor.ExplicitAttributes().Cast() - .Where(a => a.GetType().Namespace != "System.Runtime.CompilerServices").ToList(); //Do not use attributes only used by the compiler + var propertyAttributes = propertyDescriptor.ExplicitAttributes().Cast().ToList(); //Do not use attributes only used by the compiler // Generate for property string comment = string.Format(CultureInfo.CurrentCulture, Resource.CodeGen_Entity_Property_Summary_Comment, propertyName); @@ -523,8 +522,8 @@ private IEnumerable FilterTypeAttributes(AttributeCollection typeAttr List filteredAttributes = new List(); // Ignore DefaultMemberAttribute if it has been put for an indexer - IEnumerable defaultMemberAttribs = typeAttributes.Cast().Where(a => a.GetType() == typeof(DefaultMemberAttribute)); - if (defaultMemberAttribs.Any()) + List defaultMemberAttribs = new(typeAttributes.OfType()); + if (defaultMemberAttribs.Count > 0) { HashSet properties = new HashSet(TypeDescriptor.GetProperties(this.Type).Cast().Select(p => p.Name), StringComparer.Ordinal); foreach (DefaultMemberAttribute attrib in defaultMemberAttribs) @@ -538,9 +537,9 @@ private IEnumerable FilterTypeAttributes(AttributeCollection typeAttr // Filter out attributes in filteredAttributes, attributes which should only be used by the compiler, // DataContractAttribute and KnownTypeAttribute since they are handled seperatly - return typeAttributes.Cast().Where(a => a.GetType().Namespace != "System.Runtime.CompilerServices" - && a.GetType() != typeof(DataContractAttribute) && a.GetType() != typeof(KnownTypeAttribute) - && !filteredAttributes.Contains(a)); + return typeAttributes.Cast() + .Where(a => a.GetType() != typeof(DataContractAttribute) && a.GetType() != typeof(KnownTypeAttribute) + && !filteredAttributes.Contains(a)); } /// diff --git a/src/OpenRiaServices.Tools/Framework/MetadataPipeline/CustomAttributeGenerator.cs b/src/OpenRiaServices.Tools/Framework/MetadataPipeline/CustomAttributeGenerator.cs index 306566f9b..bcffc5976 100644 --- a/src/OpenRiaServices.Tools/Framework/MetadataPipeline/CustomAttributeGenerator.cs +++ b/src/OpenRiaServices.Tools/Framework/MetadataPipeline/CustomAttributeGenerator.cs @@ -633,6 +633,7 @@ private static bool IsAttributeBlocked(Type attributeType) return s_blockList.Contains(attributeType) // __DynamicallyInvokableAttribute might be added at compile time, don't propagate them || attributeType.FullName == "__DynamicallyInvokableAttribute" + || attributeType.Namespace == "System.Runtime.CompilerServices" ; } diff --git a/src/OpenRiaServices.Tools/Test/CodeGenDomainServices.cs b/src/OpenRiaServices.Tools/Test/CodeGenDomainServices.cs index 3bc402a66..4b9b4417b 100644 --- a/src/OpenRiaServices.Tools/Test/CodeGenDomainServices.cs +++ b/src/OpenRiaServices.Tools/Test/CodeGenDomainServices.cs @@ -254,6 +254,32 @@ public void TestClientCodegen_IncludeScenarios() typeof(TestDomainServices.IncludeScenariosTestProvider), sharedFiles, false)); } + [TestMethod] + [DeploymentItem(@"Baselines\Default\Scenarios", @"Baselines\Default\Scenarios")] + public void TestClientCodegen_EF_ComplexObject() + { + string[] sharedFiles = Array.Empty(); + + // Default + TestHelper.ValidateCodeGen(new TestHelper.CodeGenValidationOptions(@"Default\Scenarios", @"Baselines\Default\Scenarios", "EF_ComplexObject.g", + typeof(EFComplexTypesService), sharedFiles, false)); + } + +#if NET + // in NET472 the navigation properties to "Owned" types are Required, just as for EF6 + // - We should probably try to update the model so it matches for net6-8 + [TestMethod] + [DeploymentItem(@"Baselines\Default\Scenarios", @"Baselines\Default\Scenarios")] + public void TestClientCodegen_EFCore_ComplexObject() + { + string[] sharedFiles = Array.Empty(); + + // Default + TestHelper.ValidateCodeGen(new TestHelper.CodeGenValidationOptions(@"Default\Scenarios", @"Baselines\Default\Scenarios", "EFCore_ComplexObject.g", + typeof(EFCoreComplexTypesService), sharedFiles, false)); + } +#endif + [DeploymentItem(@"Baselines\Default\Scenarios", "CG_Scenarios_Inherit")] [TestMethod] public void TestClientCodegen_InheritanceScenarios() @@ -1010,4 +1036,22 @@ public void TestClientCodeGen_RTO_EntityWithRoundtripOriginalOnMember() @"[DataMember()] [RoundtripOriginal()] public string PropWithPropLevelRTO"); } } + + [EnableClientAccess] + public class EFComplexTypesService : OpenRiaServices.EntityFramework.LinqToEntitiesDomainService + { + public IQueryable GetCustomers() + { + return null; + } + } + + [EnableClientAccess] + public class EFCoreComplexTypesService : OpenRiaServices.Server.EntityFrameworkCore.DbDomainService + { + public IQueryable GetCustomers() + { + return null; + } + } } diff --git a/src/OpenRiaServices.Tools/Test/TestHelper.cs b/src/OpenRiaServices.Tools/Test/TestHelper.cs index 0ee941e59..77c337d33 100644 --- a/src/OpenRiaServices.Tools/Test/TestHelper.cs +++ b/src/OpenRiaServices.Tools/Test/TestHelper.cs @@ -102,7 +102,7 @@ public static bool FilesMatch(string relativeTestDir, string relativeDeployDir, using (StreamWriter sw = new StreamWriter(updateAllBatFile, true)) { - sw.Write("cmd /c " + copyCommand); + sw.Write("cmd /c "); sw.WriteLine(copyCommand); } diff --git a/src/RiaServices.sln b/src/RiaServices.sln index 8b806a39a..25d72b90a 100644 --- a/src/RiaServices.sln +++ b/src/RiaServices.sln @@ -155,6 +155,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenRiaservices.EndToEnd.Wc EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenRiaservices.EndToEnd.AspNetCore.Test", "Test\OpenRiaservices.EndToEnd.AspNetCore.Test\OpenRiaservices.EndToEnd.AspNetCore.Test.csproj", "{17F902F4-7254-4FB9-9AF6-B3291B129B45}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRiaServices.Server.EntityFrameworkCore.Test", "OpenRiaServices.Server.EntityFrameworkCore\Test\OpenRiaServices.Server.EntityFrameworkCore.Test\OpenRiaServices.Server.EntityFrameworkCore.Test.csproj", "{76DBD075-9DC2-4583-8BAB-2713E60F555B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -377,6 +379,10 @@ Global {17F902F4-7254-4FB9-9AF6-B3291B129B45}.Debug|Any CPU.Build.0 = Debug|Any CPU {17F902F4-7254-4FB9-9AF6-B3291B129B45}.Release|Any CPU.ActiveCfg = Release|Any CPU {17F902F4-7254-4FB9-9AF6-B3291B129B45}.Release|Any CPU.Build.0 = Release|Any CPU + {76DBD075-9DC2-4583-8BAB-2713E60F555B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {76DBD075-9DC2-4583-8BAB-2713E60F555B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {76DBD075-9DC2-4583-8BAB-2713E60F555B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {76DBD075-9DC2-4583-8BAB-2713E60F555B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -449,6 +455,7 @@ Global {27DB096E-8794-4B9A-B3D0-AF74926DF9FD} = {BB0E26DD-14D3-4CD5-8F2B-B5C1CA281719} {9428260A-EA94-430D-9A1A-CB9830B9E8EE} = {27DB096E-8794-4B9A-B3D0-AF74926DF9FD} {17F902F4-7254-4FB9-9AF6-B3291B129B45} = {27DB096E-8794-4B9A-B3D0-AF74926DF9FD} + {76DBD075-9DC2-4583-8BAB-2713E60F555B} = {E8CAC11B-50B6-4243-A12A-D831EBB064CB} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C135CEC9-180C-4B67-92AC-3342375AE14C} diff --git a/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/Baselines/Default/Scenarios/EFCore_ComplexObject.g.cs b/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/Baselines/Default/Scenarios/EFCore_ComplexObject.g.cs new file mode 100644 index 000000000..a307e33d8 --- /dev/null +++ b/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/Baselines/Default/Scenarios/EFCore_ComplexObject.g.cs @@ -0,0 +1,802 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace EFCoreModels.Scenarios.OwnedTypes +{ + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.ComponentModel.DataAnnotations; + using System.Linq; + using System.Runtime.Serialization; + using System.Threading.Tasks; + using OpenRiaServices; + using OpenRiaServices.Client; + using OpenRiaServices.Client.Authentication; + + + /// + /// The 'Address' class. + /// + [DataContract(Namespace="http://schemas.datacontract.org/2004/07/EFCoreModels.Scenarios.OwnedTypes")] + public sealed partial class Address : ComplexObject + { + + private string _addressLine; + + private string _city; + + #region Extensibility Method Definitions + + /// + /// This method is invoked from the constructor once initialization is complete and + /// can be used for further object setup. + /// + partial void OnCreated(); + partial void OnAddressLineChanging(string value); + partial void OnAddressLineChanged(); + partial void OnCityChanging(string value); + partial void OnCityChanged(); + + #endregion + + + /// + /// Initializes a new instance of the class. + /// + public Address() + { + this.OnCreated(); + } + + /// + /// Gets or sets the 'AddressLine' value. + /// + [DataMember()] + [Required()] + [StringLength(100)] + public string AddressLine + { + get + { + return this._addressLine; + } + set + { + if ((this._addressLine != value)) + { + this.OnAddressLineChanging(value); + this.RaiseDataMemberChanging("AddressLine"); + this.ValidateProperty("AddressLine", value); + this._addressLine = value; + this.RaiseDataMemberChanged("AddressLine"); + this.OnAddressLineChanged(); + } + } + } + + /// + /// Gets or sets the 'City' value. + /// + [DataMember()] + [Required()] + [StringLength(50)] + public string City + { + get + { + return this._city; + } + set + { + if ((this._city != value)) + { + this.OnCityChanging(value); + this.RaiseDataMemberChanging("City"); + this.ValidateProperty("City", value); + this._city = value; + this.RaiseDataMemberChanged("City"); + this.OnCityChanged(); + } + } + } + } + + /// + /// The 'ContactInfo' class. + /// + [DataContract(Namespace="http://schemas.datacontract.org/2004/07/EFCoreModels.Scenarios.OwnedTypes")] + public sealed partial class ContactInfo : ComplexObject + { + + private Address _address; + + private string _homePhone; + + #region Extensibility Method Definitions + + /// + /// This method is invoked from the constructor once initialization is complete and + /// can be used for further object setup. + /// + partial void OnCreated(); + partial void OnAddressChanging(Address value); + partial void OnAddressChanged(); + partial void OnHomePhoneChanging(string value); + partial void OnHomePhoneChanged(); + + #endregion + + + /// + /// Initializes a new instance of the class. + /// + public ContactInfo() + { + this.OnCreated(); + } + + /// + /// Gets or sets the 'Address' value. + /// + [DataMember()] + [Display(AutoGenerateField=false)] + public Address Address + { + get + { + return this._address; + } + set + { + if ((this._address != value)) + { + this.OnAddressChanging(value); + this.RaiseDataMemberChanging("Address"); + this.ValidateProperty("Address", value); + this._address = value; + this.RaiseDataMemberChanged("Address"); + this.OnAddressChanged(); + } + } + } + + /// + /// Gets or sets the 'HomePhone' value. + /// + [DataMember()] + [Required()] + [StringLength(24)] + public string HomePhone + { + get + { + return this._homePhone; + } + set + { + if ((this._homePhone != value)) + { + this.OnHomePhoneChanging(value); + this.RaiseDataMemberChanging("HomePhone"); + this.ValidateProperty("HomePhone", value); + this._homePhone = value; + this.RaiseDataMemberChanged("HomePhone"); + this.OnHomePhoneChanged(); + } + } + } + } + + /// + /// The 'Employee' entity class. + /// + [DataContract(Namespace="http://schemas.datacontract.org/2004/07/EFCoreModels.Scenarios.OwnedTypes")] + public sealed partial class Employee : Entity + { + + private ContactInfo _contactInfo; + + private int _employeeId; + + private OwnedEntityWithBackNavigation _ownedEntityWithBackNavigation; + + private EntityRef _ownedEntityWithExplicitId; + + private EntityRef _ownedEntityWithExplicitIdAndBackNavigation; + + #region Extensibility Method Definitions + + /// + /// This method is invoked from the constructor once initialization is complete and + /// can be used for further object setup. + /// + partial void OnCreated(); + partial void OnContactInfoChanging(ContactInfo value); + partial void OnContactInfoChanged(); + partial void OnEmployeeIdChanging(int value); + partial void OnEmployeeIdChanged(); + partial void OnOwnedEntityWithBackNavigationChanging(OwnedEntityWithBackNavigation value); + partial void OnOwnedEntityWithBackNavigationChanged(); + + #endregion + + + /// + /// Initializes a new instance of the class. + /// + public Employee() + { + this.OnCreated(); + } + + /// + /// Gets or sets the 'ContactInfo' value. + /// + [DataMember()] + [Display(AutoGenerateField=false)] + public ContactInfo ContactInfo + { + get + { + return this._contactInfo; + } + set + { + if ((this._contactInfo != value)) + { + this.OnContactInfoChanging(value); + this.RaiseDataMemberChanging("ContactInfo"); + this.ValidateProperty("ContactInfo", value); + this._contactInfo = value; + this.RaiseDataMemberChanged("ContactInfo"); + this.OnContactInfoChanged(); + } + } + } + + /// + /// Gets or sets the 'EmployeeId' value. + /// + [DataMember()] + [Editable(false, AllowInitialValue=true)] + [Key()] + [RoundtripOriginal()] + public int EmployeeId + { + get + { + return this._employeeId; + } + set + { + if ((this._employeeId != value)) + { + this.OnEmployeeIdChanging(value); + this.ValidateProperty("EmployeeId", value); + this._employeeId = value; + this.RaisePropertyChanged("EmployeeId"); + this.OnEmployeeIdChanged(); + } + } + } + + /// + /// Gets or sets the 'OwnedEntityWithBackNavigation' value. + /// + [DataMember()] + [Display(AutoGenerateField=false)] + public OwnedEntityWithBackNavigation OwnedEntityWithBackNavigation + { + get + { + return this._ownedEntityWithBackNavigation; + } + set + { + if ((this._ownedEntityWithBackNavigation != value)) + { + this.OnOwnedEntityWithBackNavigationChanging(value); + this.RaiseDataMemberChanging("OwnedEntityWithBackNavigation"); + this.ValidateProperty("OwnedEntityWithBackNavigation", value); + this._ownedEntityWithBackNavigation = value; + this.RaiseDataMemberChanged("OwnedEntityWithBackNavigation"); + this.OnOwnedEntityWithBackNavigationChanged(); + } + } + } + + /// + /// Gets or sets the associated entity. + /// + [Association("FK_Employees_Employees_EmployeeId|owns:OwnedEntityWithExplicitId", "EmployeeId", "EmployeeId")] + [Composition()] + public OwnedEntityWithExplicitId OwnedEntityWithExplicitId + { + get + { + if ((this._ownedEntityWithExplicitId == null)) + { + this._ownedEntityWithExplicitId = new EntityRef(this, "OwnedEntityWithExplicitId", this.FilterOwnedEntityWithExplicitId); + } + return this._ownedEntityWithExplicitId.Entity; + } + set + { + OwnedEntityWithExplicitId previous = this.OwnedEntityWithExplicitId; + if ((previous != value)) + { + this.ValidateProperty("OwnedEntityWithExplicitId", value); + this._ownedEntityWithExplicitId.Entity = value; + this.RaisePropertyChanged("OwnedEntityWithExplicitId"); + } + } + } + + /// + /// Gets or sets the associated entity. + /// + [Association("FK_Employees_Employees_EmployeeId|owns:OwnedEntityWithExplicitIdAndBackNavigation" + + "", "EmployeeId", "EmployeeId")] + [Composition()] + public OwnedEntityWithExplicitIdAndBackNavigation OwnedEntityWithExplicitIdAndBackNavigation + { + get + { + if ((this._ownedEntityWithExplicitIdAndBackNavigation == null)) + { + this._ownedEntityWithExplicitIdAndBackNavigation = new EntityRef(this, "OwnedEntityWithExplicitIdAndBackNavigation", this.FilterOwnedEntityWithExplicitIdAndBackNavigation); + } + return this._ownedEntityWithExplicitIdAndBackNavigation.Entity; + } + set + { + OwnedEntityWithExplicitIdAndBackNavigation previous = this.OwnedEntityWithExplicitIdAndBackNavigation; + if ((previous != value)) + { + this.ValidateProperty("OwnedEntityWithExplicitIdAndBackNavigation", value); + this._ownedEntityWithExplicitIdAndBackNavigation.Entity = value; + this.RaisePropertyChanged("OwnedEntityWithExplicitIdAndBackNavigation"); + } + } + } + + private bool FilterOwnedEntityWithExplicitId(OwnedEntityWithExplicitId entity) + { + return (entity.EmployeeId == this.EmployeeId); + } + + private bool FilterOwnedEntityWithExplicitIdAndBackNavigation(OwnedEntityWithExplicitIdAndBackNavigation entity) + { + return (entity.EmployeeId == this.EmployeeId); + } + + /// + /// Computes a value from the key fields that uniquely identifies this entity instance. + /// + /// An object instance that uniquely identifies this entity instance. + public override object GetIdentity() + { + return this._employeeId; + } + } + + /// + /// The 'OwnedEntityWithBackNavigation' class. + /// + [DataContract(Namespace="http://schemas.datacontract.org/2004/07/EFCoreModels.Scenarios.OwnedTypes")] + public sealed partial class OwnedEntityWithBackNavigation : ComplexObject + { + + private string _description; + + #region Extensibility Method Definitions + + /// + /// This method is invoked from the constructor once initialization is complete and + /// can be used for further object setup. + /// + partial void OnCreated(); + partial void OnDescriptionChanging(string value); + partial void OnDescriptionChanged(); + + #endregion + + + /// + /// Initializes a new instance of the class. + /// + public OwnedEntityWithBackNavigation() + { + this.OnCreated(); + } + + /// + /// Gets or sets the 'Description' value. + /// + [DataMember()] + [Required()] + public string Description + { + get + { + return this._description; + } + set + { + if ((this._description != value)) + { + this.OnDescriptionChanging(value); + this.RaiseDataMemberChanging("Description"); + this.ValidateProperty("Description", value); + this._description = value; + this.RaiseDataMemberChanged("Description"); + this.OnDescriptionChanged(); + } + } + } + } + + /// + /// The 'OwnedEntityWithExplicitId' entity class. + /// + [DataContract(Namespace="http://schemas.datacontract.org/2004/07/EFCoreModels.Scenarios.OwnedTypes")] + public sealed partial class OwnedEntityWithExplicitId : Entity + { + + private string _description; + + private int _employeeId; + + #region Extensibility Method Definitions + + /// + /// This method is invoked from the constructor once initialization is complete and + /// can be used for further object setup. + /// + partial void OnCreated(); + partial void OnDescriptionChanging(string value); + partial void OnDescriptionChanged(); + partial void OnEmployeeIdChanging(int value); + partial void OnEmployeeIdChanged(); + + #endregion + + + /// + /// Initializes a new instance of the class. + /// + public OwnedEntityWithExplicitId() + { + this.OnCreated(); + } + + /// + /// Gets or sets the 'Description' value. + /// + [DataMember()] + [Required()] + public string Description + { + get + { + return this._description; + } + set + { + if ((this._description != value)) + { + this.OnDescriptionChanging(value); + this.RaiseDataMemberChanging("Description"); + this.ValidateProperty("Description", value); + this._description = value; + this.RaiseDataMemberChanged("Description"); + this.OnDescriptionChanged(); + } + } + } + + /// + /// Gets or sets the 'EmployeeId' value. + /// + [DataMember()] + [Editable(false, AllowInitialValue=true)] + [Key()] + [RoundtripOriginal()] + public int EmployeeId + { + get + { + return this._employeeId; + } + set + { + if ((this._employeeId != value)) + { + this.OnEmployeeIdChanging(value); + this.ValidateProperty("EmployeeId", value); + this._employeeId = value; + this.RaisePropertyChanged("EmployeeId"); + this.OnEmployeeIdChanged(); + } + } + } + + /// + /// Computes a value from the key fields that uniquely identifies this entity instance. + /// + /// An object instance that uniquely identifies this entity instance. + public override object GetIdentity() + { + return this._employeeId; + } + } + + /// + /// The 'OwnedEntityWithExplicitIdAndBackNavigation' entity class. + /// + [DataContract(Namespace="http://schemas.datacontract.org/2004/07/EFCoreModels.Scenarios.OwnedTypes")] + public sealed partial class OwnedEntityWithExplicitIdAndBackNavigation : Entity + { + + private string _description; + + private EntityRef _employee; + + private int _employeeId; + + #region Extensibility Method Definitions + + /// + /// This method is invoked from the constructor once initialization is complete and + /// can be used for further object setup. + /// + partial void OnCreated(); + partial void OnDescriptionChanging(string value); + partial void OnDescriptionChanged(); + partial void OnEmployeeIdChanging(int value); + partial void OnEmployeeIdChanged(); + + #endregion + + + /// + /// Initializes a new instance of the class. + /// + public OwnedEntityWithExplicitIdAndBackNavigation() + { + this.OnCreated(); + } + + /// + /// Gets or sets the 'Description' value. + /// + [DataMember()] + [Required()] + public string Description + { + get + { + return this._description; + } + set + { + if ((this._description != value)) + { + this.OnDescriptionChanging(value); + this.RaiseDataMemberChanging("Description"); + this.ValidateProperty("Description", value); + this._description = value; + this.RaiseDataMemberChanged("Description"); + this.OnDescriptionChanged(); + } + } + } + + /// + /// Gets or sets the associated entity. + /// + [Association("FK_Employees_Employees_EmployeeId", "EmployeeId", "EmployeeId", IsForeignKey=true)] + public Employee Employee + { + get + { + if ((this._employee == null)) + { + this._employee = new EntityRef(this, "Employee", this.FilterEmployee); + } + return this._employee.Entity; + } + set + { + Employee previous = this.Employee; + if ((previous != value)) + { + this.ValidateProperty("Employee", value); + if ((value != null)) + { + this.EmployeeId = value.EmployeeId; + } + else + { + this.EmployeeId = default(int); + } + this._employee.Entity = value; + this.RaisePropertyChanged("Employee"); + } + } + } + + /// + /// Gets or sets the 'EmployeeId' value. + /// + [DataMember()] + [Editable(false, AllowInitialValue=true)] + [Key()] + [RoundtripOriginal()] + public int EmployeeId + { + get + { + return this._employeeId; + } + set + { + if ((this._employeeId != value)) + { + this.OnEmployeeIdChanging(value); + this.ValidateProperty("EmployeeId", value); + this._employeeId = value; + this.RaisePropertyChanged("EmployeeId"); + this.OnEmployeeIdChanged(); + } + } + } + + private bool FilterEmployee(Employee entity) + { + return (entity.EmployeeId == this.EmployeeId); + } + + /// + /// Computes a value from the key fields that uniquely identifies this entity instance. + /// + /// An object instance that uniquely identifies this entity instance. + public override object GetIdentity() + { + return this._employeeId; + } + } +} +namespace OpenRiaServices.Tools.Test +{ + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.ComponentModel.DataAnnotations; + using System.Linq; + using System.ServiceModel; + using System.Threading.Tasks; + using EFCoreModels.Scenarios.OwnedTypes; + using OpenRiaServices; + using OpenRiaServices.Client; + using OpenRiaServices.Client.Authentication; + + + /// + /// The DomainContext corresponding to the 'EFCoreComplexTypesService' DomainService. + /// + public sealed partial class EFCoreComplexTypesContext : DomainContext + { + + #region Extensibility Method Definitions + + /// + /// This method is invoked from the constructor once initialization is complete and + /// can be used for further object setup. + /// + partial void OnCreated(); + + #endregion + + + /// + /// Initializes a new instance of the class. + /// + public EFCoreComplexTypesContext() : + this(new Uri("OpenRiaServices-Tools-Test-EFCoreComplexTypesService.svc", UriKind.Relative)) + { + } + + /// + /// Initializes a new instance of the class with the specified service URI. + /// + /// The EFCoreComplexTypesService service URI. + public EFCoreComplexTypesContext(Uri serviceUri) : + this(DomainContext.CreateDomainClient(typeof(IEFCoreComplexTypesServiceContract), serviceUri, false)) + { + } + + /// + /// Initializes a new instance of the class with the specified . + /// + /// The DomainClient instance to use for this DomainContext. + public EFCoreComplexTypesContext(DomainClient domainClient) : + base(domainClient) + { + this.OnCreated(); + } + + /// + /// Gets the set of entity instances that have been loaded into this instance. + /// + public EntitySet Employees + { + get + { + return base.EntityContainer.GetEntitySet(); + } + } + + /// + /// Gets an EntityQuery instance that can be used to load entity instances using the 'GetCustomers' query. + /// + /// An EntityQuery that can be loaded to retrieve entity instances. + public EntityQuery GetCustomersQuery() + { + this.ValidateMethod("GetCustomersQuery", null); + return base.CreateQuery("GetCustomers", null, false, true); + } + + /// + /// Creates a new EntityContainer for this DomainContext's EntitySets. + /// + /// A new container instance. + protected override EntityContainer CreateEntityContainer() + { + return new EFCoreComplexTypesContextEntityContainer(); + } + + /// + /// Service contract for the 'EFCoreComplexTypesService' DomainService. + /// + [ServiceContract()] + public interface IEFCoreComplexTypesServiceContract + { + + /// + /// Asynchronously invokes the 'GetCustomers' operation. + /// + /// Callback to invoke on completion. + /// Optional state object. + /// An IAsyncResult that can be used to monitor the request. + [HasSideEffects(false)] + [OperationContract(AsyncPattern=true, Action="http://tempuri.org/EFCoreComplexTypesService/GetCustomers", ReplyAction="http://tempuri.org/EFCoreComplexTypesService/GetCustomersResponse")] + IAsyncResult BeginGetCustomers(AsyncCallback callback, object asyncState); + + /// + /// Completes the asynchronous operation begun by 'BeginGetCustomers'. + /// + /// The IAsyncResult returned from 'BeginGetCustomers'. + /// The 'QueryResult' returned from the 'GetCustomers' operation. + QueryResult EndGetCustomers(IAsyncResult result); + } + + internal sealed class EFCoreComplexTypesContextEntityContainer : EntityContainer + { + + public EFCoreComplexTypesContextEntityContainer() + { + this.CreateEntitySet(EntitySetOperations.None); + this.CreateEntitySet(EntitySetOperations.None); + this.CreateEntitySet(EntitySetOperations.None); + } + } + } +} diff --git a/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/Baselines/Default/Scenarios/EFCore_ComplexObject.g.vb b/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/Baselines/Default/Scenarios/EFCore_ComplexObject.g.vb new file mode 100644 index 000000000..2c3626323 --- /dev/null +++ b/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/Baselines/Default/Scenarios/EFCore_ComplexObject.g.vb @@ -0,0 +1,750 @@ +'------------------------------------------------------------------------------ +' +' This code was generated by a tool. +' +' Changes to this file may cause incorrect behavior and will be lost if +' the code is regenerated. +' +'------------------------------------------------------------------------------ + +Option Compare Binary +Option Infer On +Option Strict On +Option Explicit On + +Imports EFCoreModels.Scenarios.OwnedTypes +Imports OpenRiaServices +Imports OpenRiaServices.Client +Imports OpenRiaServices.Client.Authentication +Imports System +Imports System.Collections.Generic +Imports System.ComponentModel +Imports System.ComponentModel.DataAnnotations +Imports System.Linq +Imports System.Runtime.Serialization +Imports System.ServiceModel +Imports System.Threading.Tasks + +Namespace EFCoreModels.Scenarios.OwnedTypes + + ''' + ''' The 'Address' class. + ''' + _ + Partial Public NotInheritable Class Address + Inherits ComplexObject + + Private _addressLine As String + + Private _city As String + + #Region "Extensibility Method Definitions" + + ''' + ''' This method is invoked from the constructor once initialization is complete and + ''' can be used for further object setup. + ''' + Private Partial Sub OnCreated() + End Sub + Private Partial Sub OnAddressLineChanging(ByVal value As String) + End Sub + Private Partial Sub OnAddressLineChanged() + End Sub + Private Partial Sub OnCityChanging(ByVal value As String) + End Sub + Private Partial Sub OnCityChanged() + End Sub + + #End Region + + + ''' + ''' Initializes a new instance of the class. + ''' + Public Sub New() + MyBase.New + Me.OnCreated + End Sub + + ''' + ''' Gets or sets the 'AddressLine' value. + ''' + _ + Public Property AddressLine() As String + Get + Return Me._addressLine + End Get + Set + If (String.Equals(Me._addressLine, value) = false) Then + Me.OnAddressLineChanging(value) + Me.RaiseDataMemberChanging("AddressLine") + Me.ValidateProperty("AddressLine", value) + Me._addressLine = value + Me.RaiseDataMemberChanged("AddressLine") + Me.OnAddressLineChanged + End If + End Set + End Property + + ''' + ''' Gets or sets the 'City' value. + ''' + _ + Public Property City() As String + Get + Return Me._city + End Get + Set + If (String.Equals(Me._city, value) = false) Then + Me.OnCityChanging(value) + Me.RaiseDataMemberChanging("City") + Me.ValidateProperty("City", value) + Me._city = value + Me.RaiseDataMemberChanged("City") + Me.OnCityChanged + End If + End Set + End Property + End Class + + ''' + ''' The 'ContactInfo' class. + ''' + _ + Partial Public NotInheritable Class ContactInfo + Inherits ComplexObject + + Private _address As Address + + Private _homePhone As String + + #Region "Extensibility Method Definitions" + + ''' + ''' This method is invoked from the constructor once initialization is complete and + ''' can be used for further object setup. + ''' + Private Partial Sub OnCreated() + End Sub + Private Partial Sub OnAddressChanging(ByVal value As Address) + End Sub + Private Partial Sub OnAddressChanged() + End Sub + Private Partial Sub OnHomePhoneChanging(ByVal value As String) + End Sub + Private Partial Sub OnHomePhoneChanged() + End Sub + + #End Region + + + ''' + ''' Initializes a new instance of the class. + ''' + Public Sub New() + MyBase.New + Me.OnCreated + End Sub + + ''' + ''' Gets or sets the 'Address' value. + ''' + _ + Public Property Address() As Address + Get + Return Me._address + End Get + Set + If (Object.Equals(Me._address, value) = false) Then + Me.OnAddressChanging(value) + Me.RaiseDataMemberChanging("Address") + Me.ValidateProperty("Address", value) + Me._address = value + Me.RaiseDataMemberChanged("Address") + Me.OnAddressChanged + End If + End Set + End Property + + ''' + ''' Gets or sets the 'HomePhone' value. + ''' + _ + Public Property HomePhone() As String + Get + Return Me._homePhone + End Get + Set + If (String.Equals(Me._homePhone, value) = false) Then + Me.OnHomePhoneChanging(value) + Me.RaiseDataMemberChanging("HomePhone") + Me.ValidateProperty("HomePhone", value) + Me._homePhone = value + Me.RaiseDataMemberChanged("HomePhone") + Me.OnHomePhoneChanged + End If + End Set + End Property + End Class + + ''' + ''' The 'Employee' entity class. + ''' + _ + Partial Public NotInheritable Class Employee + Inherits Entity + + Private _contactInfo As ContactInfo + + Private _employeeId As Integer + + Private _ownedEntityWithBackNavigation As OwnedEntityWithBackNavigation + + Private _ownedEntityWithExplicitId As EntityRef(Of OwnedEntityWithExplicitId) + + Private _ownedEntityWithExplicitIdAndBackNavigation As EntityRef(Of OwnedEntityWithExplicitIdAndBackNavigation) + + #Region "Extensibility Method Definitions" + + ''' + ''' This method is invoked from the constructor once initialization is complete and + ''' can be used for further object setup. + ''' + Private Partial Sub OnCreated() + End Sub + Private Partial Sub OnContactInfoChanging(ByVal value As ContactInfo) + End Sub + Private Partial Sub OnContactInfoChanged() + End Sub + Private Partial Sub OnEmployeeIdChanging(ByVal value As Integer) + End Sub + Private Partial Sub OnEmployeeIdChanged() + End Sub + Private Partial Sub OnOwnedEntityWithBackNavigationChanging(ByVal value As OwnedEntityWithBackNavigation) + End Sub + Private Partial Sub OnOwnedEntityWithBackNavigationChanged() + End Sub + + #End Region + + + ''' + ''' Initializes a new instance of the class. + ''' + Public Sub New() + MyBase.New + Me.OnCreated + End Sub + + ''' + ''' Gets or sets the 'ContactInfo' value. + ''' + _ + Public Property ContactInfo() As ContactInfo + Get + Return Me._contactInfo + End Get + Set + If (Object.Equals(Me._contactInfo, value) = false) Then + Me.OnContactInfoChanging(value) + Me.RaiseDataMemberChanging("ContactInfo") + Me.ValidateProperty("ContactInfo", value) + Me._contactInfo = value + Me.RaiseDataMemberChanged("ContactInfo") + Me.OnContactInfoChanged + End If + End Set + End Property + + ''' + ''' Gets or sets the 'EmployeeId' value. + ''' + _ + Public Property EmployeeId() As Integer + Get + Return Me._employeeId + End Get + Set + If ((Me._employeeId = value) _ + = false) Then + Me.OnEmployeeIdChanging(value) + Me.ValidateProperty("EmployeeId", value) + Me._employeeId = value + Me.RaisePropertyChanged("EmployeeId") + Me.OnEmployeeIdChanged + End If + End Set + End Property + + ''' + ''' Gets or sets the 'OwnedEntityWithBackNavigation' value. + ''' + _ + Public Property OwnedEntityWithBackNavigation() As OwnedEntityWithBackNavigation + Get + Return Me._ownedEntityWithBackNavigation + End Get + Set + If (Object.Equals(Me._ownedEntityWithBackNavigation, value) = false) Then + Me.OnOwnedEntityWithBackNavigationChanging(value) + Me.RaiseDataMemberChanging("OwnedEntityWithBackNavigation") + Me.ValidateProperty("OwnedEntityWithBackNavigation", value) + Me._ownedEntityWithBackNavigation = value + Me.RaiseDataMemberChanged("OwnedEntityWithBackNavigation") + Me.OnOwnedEntityWithBackNavigationChanged + End If + End Set + End Property + + ''' + ''' Gets or sets the associated entity. + ''' + _ + Public Property OwnedEntityWithExplicitId() As OwnedEntityWithExplicitId + Get + If (Me._ownedEntityWithExplicitId Is Nothing) Then + Me._ownedEntityWithExplicitId = New EntityRef(Of OwnedEntityWithExplicitId)(Me, "OwnedEntityWithExplicitId", AddressOf Me.FilterOwnedEntityWithExplicitId) + End If + Return Me._ownedEntityWithExplicitId.Entity + End Get + Set + Dim previous As OwnedEntityWithExplicitId = Me.OwnedEntityWithExplicitId + If (Object.Equals(previous, value) = false) Then + Me.ValidateProperty("OwnedEntityWithExplicitId", value) + Me._ownedEntityWithExplicitId.Entity = value + Me.RaisePropertyChanged("OwnedEntityWithExplicitId") + End If + End Set + End Property + + ''' + ''' Gets or sets the associated entity. + ''' + _ + Public Property OwnedEntityWithExplicitIdAndBackNavigation() As OwnedEntityWithExplicitIdAndBackNavigation + Get + If (Me._ownedEntityWithExplicitIdAndBackNavigation Is Nothing) Then + Me._ownedEntityWithExplicitIdAndBackNavigation = New EntityRef(Of OwnedEntityWithExplicitIdAndBackNavigation)(Me, "OwnedEntityWithExplicitIdAndBackNavigation", AddressOf Me.FilterOwnedEntityWithExplicitIdAndBackNavigation) + End If + Return Me._ownedEntityWithExplicitIdAndBackNavigation.Entity + End Get + Set + Dim previous As OwnedEntityWithExplicitIdAndBackNavigation = Me.OwnedEntityWithExplicitIdAndBackNavigation + If (Object.Equals(previous, value) = false) Then + Me.ValidateProperty("OwnedEntityWithExplicitIdAndBackNavigation", value) + Me._ownedEntityWithExplicitIdAndBackNavigation.Entity = value + Me.RaisePropertyChanged("OwnedEntityWithExplicitIdAndBackNavigation") + End If + End Set + End Property + + Private Function FilterOwnedEntityWithExplicitId(ByVal entity As OwnedEntityWithExplicitId) As Boolean + Return Object.Equals(entity.EmployeeId, Me.EmployeeId) + End Function + + Private Function FilterOwnedEntityWithExplicitIdAndBackNavigation(ByVal entity As OwnedEntityWithExplicitIdAndBackNavigation) As Boolean + Return Object.Equals(entity.EmployeeId, Me.EmployeeId) + End Function + + ''' + ''' Computes a value from the key fields that uniquely identifies this entity instance. + ''' + ''' An object instance that uniquely identifies this entity instance. + Public Overrides Function GetIdentity() As Object + Return Me._employeeId + End Function + End Class + + ''' + ''' The 'OwnedEntityWithBackNavigation' class. + ''' + _ + Partial Public NotInheritable Class OwnedEntityWithBackNavigation + Inherits ComplexObject + + Private _description As String + + #Region "Extensibility Method Definitions" + + ''' + ''' This method is invoked from the constructor once initialization is complete and + ''' can be used for further object setup. + ''' + Private Partial Sub OnCreated() + End Sub + Private Partial Sub OnDescriptionChanging(ByVal value As String) + End Sub + Private Partial Sub OnDescriptionChanged() + End Sub + + #End Region + + + ''' + ''' Initializes a new instance of the class. + ''' + Public Sub New() + MyBase.New + Me.OnCreated + End Sub + + ''' + ''' Gets or sets the 'Description' value. + ''' + _ + Public Property Description() As String + Get + Return Me._description + End Get + Set + If (String.Equals(Me._description, value) = false) Then + Me.OnDescriptionChanging(value) + Me.RaiseDataMemberChanging("Description") + Me.ValidateProperty("Description", value) + Me._description = value + Me.RaiseDataMemberChanged("Description") + Me.OnDescriptionChanged + End If + End Set + End Property + End Class + + ''' + ''' The 'OwnedEntityWithExplicitId' entity class. + ''' + _ + Partial Public NotInheritable Class OwnedEntityWithExplicitId + Inherits Entity + + Private _description As String + + Private _employeeId As Integer + + #Region "Extensibility Method Definitions" + + ''' + ''' This method is invoked from the constructor once initialization is complete and + ''' can be used for further object setup. + ''' + Private Partial Sub OnCreated() + End Sub + Private Partial Sub OnDescriptionChanging(ByVal value As String) + End Sub + Private Partial Sub OnDescriptionChanged() + End Sub + Private Partial Sub OnEmployeeIdChanging(ByVal value As Integer) + End Sub + Private Partial Sub OnEmployeeIdChanged() + End Sub + + #End Region + + + ''' + ''' Initializes a new instance of the class. + ''' + Public Sub New() + MyBase.New + Me.OnCreated + End Sub + + ''' + ''' Gets or sets the 'Description' value. + ''' + _ + Public Property Description() As String + Get + Return Me._description + End Get + Set + If (String.Equals(Me._description, value) = false) Then + Me.OnDescriptionChanging(value) + Me.RaiseDataMemberChanging("Description") + Me.ValidateProperty("Description", value) + Me._description = value + Me.RaiseDataMemberChanged("Description") + Me.OnDescriptionChanged + End If + End Set + End Property + + ''' + ''' Gets or sets the 'EmployeeId' value. + ''' + _ + Public Property EmployeeId() As Integer + Get + Return Me._employeeId + End Get + Set + If ((Me._employeeId = value) _ + = false) Then + Me.OnEmployeeIdChanging(value) + Me.ValidateProperty("EmployeeId", value) + Me._employeeId = value + Me.RaisePropertyChanged("EmployeeId") + Me.OnEmployeeIdChanged + End If + End Set + End Property + + ''' + ''' Computes a value from the key fields that uniquely identifies this entity instance. + ''' + ''' An object instance that uniquely identifies this entity instance. + Public Overrides Function GetIdentity() As Object + Return Me._employeeId + End Function + End Class + + ''' + ''' The 'OwnedEntityWithExplicitIdAndBackNavigation' entity class. + ''' + _ + Partial Public NotInheritable Class OwnedEntityWithExplicitIdAndBackNavigation + Inherits Entity + + Private _description As String + + Private _employee As EntityRef(Of Employee) + + Private _employeeId As Integer + + #Region "Extensibility Method Definitions" + + ''' + ''' This method is invoked from the constructor once initialization is complete and + ''' can be used for further object setup. + ''' + Private Partial Sub OnCreated() + End Sub + Private Partial Sub OnDescriptionChanging(ByVal value As String) + End Sub + Private Partial Sub OnDescriptionChanged() + End Sub + Private Partial Sub OnEmployeeIdChanging(ByVal value As Integer) + End Sub + Private Partial Sub OnEmployeeIdChanged() + End Sub + + #End Region + + + ''' + ''' Initializes a new instance of the class. + ''' + Public Sub New() + MyBase.New + Me.OnCreated + End Sub + + ''' + ''' Gets or sets the 'Description' value. + ''' + _ + Public Property Description() As String + Get + Return Me._description + End Get + Set + If (String.Equals(Me._description, value) = false) Then + Me.OnDescriptionChanging(value) + Me.RaiseDataMemberChanging("Description") + Me.ValidateProperty("Description", value) + Me._description = value + Me.RaiseDataMemberChanged("Description") + Me.OnDescriptionChanged + End If + End Set + End Property + + ''' + ''' Gets or sets the associated entity. + ''' + _ + Public Property Employee() As Employee + Get + If (Me._employee Is Nothing) Then + Me._employee = New EntityRef(Of Employee)(Me, "Employee", AddressOf Me.FilterEmployee) + End If + Return Me._employee.Entity + End Get + Set + Dim previous As Employee = Me.Employee + If (Object.Equals(previous, value) = false) Then + Me.ValidateProperty("Employee", value) + If (Not (value) Is Nothing) Then + Me.EmployeeId = value.EmployeeId + Else + Me.EmployeeId = CType(Nothing, Integer) + End If + Me._employee.Entity = value + Me.RaisePropertyChanged("Employee") + End If + End Set + End Property + + ''' + ''' Gets or sets the 'EmployeeId' value. + ''' + _ + Public Property EmployeeId() As Integer + Get + Return Me._employeeId + End Get + Set + If ((Me._employeeId = value) _ + = false) Then + Me.OnEmployeeIdChanging(value) + Me.ValidateProperty("EmployeeId", value) + Me._employeeId = value + Me.RaisePropertyChanged("EmployeeId") + Me.OnEmployeeIdChanged + End If + End Set + End Property + + Private Function FilterEmployee(ByVal entity As Employee) As Boolean + Return Object.Equals(entity.EmployeeId, Me.EmployeeId) + End Function + + ''' + ''' Computes a value from the key fields that uniquely identifies this entity instance. + ''' + ''' An object instance that uniquely identifies this entity instance. + Public Overrides Function GetIdentity() As Object + Return Me._employeeId + End Function + End Class +End Namespace + +Namespace OpenRiaServices.Tools.Test + + ''' + ''' The DomainContext corresponding to the 'EFCoreComplexTypesService' DomainService. + ''' + Partial Public NotInheritable Class EFCoreComplexTypesContext + Inherits DomainContext + + #Region "Extensibility Method Definitions" + + ''' + ''' This method is invoked from the constructor once initialization is complete and + ''' can be used for further object setup. + ''' + Private Partial Sub OnCreated() + End Sub + + #End Region + + + ''' + ''' Initializes a new instance of the class. + ''' + Public Sub New() + Me.New(New Uri("OpenRiaServices-Tools-Test-EFCoreComplexTypesService.svc", UriKind.Relative)) + End Sub + + ''' + ''' Initializes a new instance of the class with the specified service URI. + ''' + ''' The EFCoreComplexTypesService service URI. + Public Sub New(ByVal serviceUri As Uri) + Me.New(DomainContext.CreateDomainClient(GetType(IEFCoreComplexTypesServiceContract), serviceUri, false)) + End Sub + + ''' + ''' Initializes a new instance of the class with the specified . + ''' + ''' The DomainClient instance to use for this DomainContext. + Public Sub New(ByVal domainClient As DomainClient) + MyBase.New(domainClient) + Me.OnCreated + End Sub + + ''' + ''' Gets the set of entity instances that have been loaded into this instance. + ''' + Public ReadOnly Property Employees() As EntitySet(Of Employee) + Get + Return MyBase.EntityContainer.GetEntitySet(Of Employee) + End Get + End Property + + ''' + ''' Gets an EntityQuery instance that can be used to load entity instances using the 'GetCustomers' query. + ''' + ''' An EntityQuery that can be loaded to retrieve entity instances. + Public Function GetCustomersQuery() As EntityQuery(Of Employee) + Me.ValidateMethod("GetCustomersQuery", Nothing) + Return MyBase.CreateQuery(Of Employee)("GetCustomers", Nothing, false, true) + End Function + + ''' + ''' Creates a new EntityContainer for this DomainContext's EntitySets. + ''' + ''' A new container instance. + Protected Overrides Function CreateEntityContainer() As EntityContainer + Return New EFCoreComplexTypesContextEntityContainer() + End Function + + ''' + ''' Service contract for the 'EFCoreComplexTypesService' DomainService. + ''' + _ + Public Interface IEFCoreComplexTypesServiceContract + + ''' + ''' Asynchronously invokes the 'GetCustomers' operation. + ''' + ''' Callback to invoke on completion. + ''' Optional state object. + ''' An IAsyncResult that can be used to monitor the request. + _ + Function BeginGetCustomers(ByVal callback As AsyncCallback, ByVal asyncState As Object) As IAsyncResult + + ''' + ''' Completes the asynchronous operation begun by 'BeginGetCustomers'. + ''' + ''' The IAsyncResult returned from 'BeginGetCustomers'. + ''' The 'QueryResult' returned from the 'GetCustomers' operation. + Function EndGetCustomers(ByVal result As IAsyncResult) As QueryResult(Of Employee) + End Interface + + Friend NotInheritable Class EFCoreComplexTypesContextEntityContainer + Inherits EntityContainer + + Public Sub New() + MyBase.New + Me.CreateEntitySet(Of Employee)(EntitySetOperations.None) + Me.CreateEntitySet(Of OwnedEntityWithExplicitId)(EntitySetOperations.None) + Me.CreateEntitySet(Of OwnedEntityWithExplicitIdAndBackNavigation)(EntitySetOperations.None) + End Sub + End Class + End Class +End Namespace diff --git a/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/Baselines/Default/Scenarios/EF_ComplexObject.g.cs b/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/Baselines/Default/Scenarios/EF_ComplexObject.g.cs new file mode 100644 index 000000000..adadc8d34 --- /dev/null +++ b/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/Baselines/Default/Scenarios/EF_ComplexObject.g.cs @@ -0,0 +1,425 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace DataTests.Scenarios.EF.Northwind +{ + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.ComponentModel.DataAnnotations; + using System.Linq; + using System.Runtime.Serialization; + using System.Threading.Tasks; + using OpenRiaServices; + using OpenRiaServices.Client; + using OpenRiaServices.Client.Authentication; + + + /// + /// The 'AddressCT' class. + /// + [DataContract(Namespace="http://schemas.datacontract.org/2004/07/DataTests.Scenarios.EF.Northwind")] + public sealed partial class AddressCT : ComplexObject + { + + private string _addressLine; + + private string _city; + + #region Extensibility Method Definitions + + /// + /// This method is invoked from the constructor once initialization is complete and + /// can be used for further object setup. + /// + partial void OnCreated(); + partial void OnAddressLineChanging(string value); + partial void OnAddressLineChanged(); + partial void OnCityChanging(string value); + partial void OnCityChanged(); + + #endregion + + + /// + /// Initializes a new instance of the class. + /// + public AddressCT() + { + this.OnCreated(); + } + + /// + /// Gets or sets the 'AddressLine' value. + /// + [ConcurrencyCheck()] + [DataMember()] + [Required()] + [RoundtripOriginal()] + [StringLength(100)] + public string AddressLine + { + get + { + return this._addressLine; + } + set + { + if ((this._addressLine != value)) + { + this.OnAddressLineChanging(value); + this.RaiseDataMemberChanging("AddressLine"); + this.ValidateProperty("AddressLine", value); + this._addressLine = value; + this.RaiseDataMemberChanged("AddressLine"); + this.OnAddressLineChanged(); + } + } + } + + /// + /// Gets or sets the 'City' value. + /// + [ConcurrencyCheck()] + [DataMember()] + [Required()] + [RoundtripOriginal()] + [StringLength(50)] + public string City + { + get + { + return this._city; + } + set + { + if ((this._city != value)) + { + this.OnCityChanging(value); + this.RaiseDataMemberChanging("City"); + this.ValidateProperty("City", value); + this._city = value; + this.RaiseDataMemberChanged("City"); + this.OnCityChanged(); + } + } + } + } + + /// + /// The 'ContactInfoCT' class. + /// + [DataContract(Namespace="http://schemas.datacontract.org/2004/07/DataTests.Scenarios.EF.Northwind")] + public sealed partial class ContactInfoCT : ComplexObject + { + + private AddressCT _address; + + private string _homePhone; + + #region Extensibility Method Definitions + + /// + /// This method is invoked from the constructor once initialization is complete and + /// can be used for further object setup. + /// + partial void OnCreated(); + partial void OnAddressChanging(AddressCT value); + partial void OnAddressChanged(); + partial void OnHomePhoneChanging(string value); + partial void OnHomePhoneChanged(); + + #endregion + + + /// + /// Initializes a new instance of the class. + /// + public ContactInfoCT() + { + this.OnCreated(); + } + + /// + /// Gets or sets the 'Address' value. + /// + [DataMember()] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + [Display(AutoGenerateField=false)] + [Required()] + public AddressCT Address + { + get + { + return this._address; + } + set + { + if ((this._address != value)) + { + this.OnAddressChanging(value); + this.RaiseDataMemberChanging("Address"); + this.ValidateProperty("Address", value); + this._address = value; + this.RaiseDataMemberChanged("Address"); + this.OnAddressChanged(); + } + } + } + + /// + /// Gets or sets the 'HomePhone' value. + /// + [ConcurrencyCheck()] + [DataMember()] + [Required()] + [RoundtripOriginal()] + [StringLength(24)] + public string HomePhone + { + get + { + return this._homePhone; + } + set + { + if ((this._homePhone != value)) + { + this.OnHomePhoneChanging(value); + this.RaiseDataMemberChanging("HomePhone"); + this.ValidateProperty("HomePhone", value); + this._homePhone = value; + this.RaiseDataMemberChanged("HomePhone"); + this.OnHomePhoneChanged(); + } + } + } + } + + /// + /// The 'EmployeeWithCT' entity class. + /// + [DataContract(Namespace="http://schemas.datacontract.org/2004/07/DataTests.Scenarios.EF.Northwind")] + public sealed partial class EmployeeWithCT : Entity + { + + private ContactInfoCT _contactInfo; + + private int _employeeID; + + #region Extensibility Method Definitions + + /// + /// This method is invoked from the constructor once initialization is complete and + /// can be used for further object setup. + /// + partial void OnCreated(); + partial void OnContactInfoChanging(ContactInfoCT value); + partial void OnContactInfoChanged(); + partial void OnEmployeeIDChanging(int value); + partial void OnEmployeeIDChanged(); + + #endregion + + + /// + /// Initializes a new instance of the class. + /// + public EmployeeWithCT() + { + this.OnCreated(); + } + + /// + /// Gets or sets the 'ContactInfo' value. + /// + [DataMember()] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + [Display(AutoGenerateField=false)] + [Required()] + public ContactInfoCT ContactInfo + { + get + { + return this._contactInfo; + } + set + { + if ((this._contactInfo != value)) + { + this.OnContactInfoChanging(value); + this.RaiseDataMemberChanging("ContactInfo"); + this.ValidateProperty("ContactInfo", value); + this._contactInfo = value; + this.RaiseDataMemberChanged("ContactInfo"); + this.OnContactInfoChanged(); + } + } + } + + /// + /// Gets or sets the 'EmployeeID' value. + /// + [DataMember()] + [Editable(false, AllowInitialValue=true)] + [Key()] + [RoundtripOriginal()] + public int EmployeeID + { + get + { + return this._employeeID; + } + set + { + if ((this._employeeID != value)) + { + this.OnEmployeeIDChanging(value); + this.ValidateProperty("EmployeeID", value); + this._employeeID = value; + this.RaisePropertyChanged("EmployeeID"); + this.OnEmployeeIDChanged(); + } + } + } + + /// + /// Computes a value from the key fields that uniquely identifies this entity instance. + /// + /// An object instance that uniquely identifies this entity instance. + public override object GetIdentity() + { + return this._employeeID; + } + } +} +namespace OpenRiaServices.Tools.Test +{ + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.ComponentModel.DataAnnotations; + using System.Linq; + using System.ServiceModel; + using System.Threading.Tasks; + using DataTests.Scenarios.EF.Northwind; + using OpenRiaServices; + using OpenRiaServices.Client; + using OpenRiaServices.Client.Authentication; + + + /// + /// The DomainContext corresponding to the 'EFComplexTypesService' DomainService. + /// + public sealed partial class EFComplexTypesContext : DomainContext + { + + #region Extensibility Method Definitions + + /// + /// This method is invoked from the constructor once initialization is complete and + /// can be used for further object setup. + /// + partial void OnCreated(); + + #endregion + + + /// + /// Initializes a new instance of the class. + /// + public EFComplexTypesContext() : + this(new Uri("OpenRiaServices-Tools-Test-EFComplexTypesService.svc", UriKind.Relative)) + { + } + + /// + /// Initializes a new instance of the class with the specified service URI. + /// + /// The EFComplexTypesService service URI. + public EFComplexTypesContext(Uri serviceUri) : + this(DomainContext.CreateDomainClient(typeof(IEFComplexTypesServiceContract), serviceUri, false)) + { + } + + /// + /// Initializes a new instance of the class with the specified . + /// + /// The DomainClient instance to use for this DomainContext. + public EFComplexTypesContext(DomainClient domainClient) : + base(domainClient) + { + this.OnCreated(); + } + + /// + /// Gets the set of entity instances that have been loaded into this instance. + /// + public EntitySet EmployeeWithCTs + { + get + { + return base.EntityContainer.GetEntitySet(); + } + } + + /// + /// Gets an EntityQuery instance that can be used to load entity instances using the 'GetCustomers' query. + /// + /// An EntityQuery that can be loaded to retrieve entity instances. + public EntityQuery GetCustomersQuery() + { + this.ValidateMethod("GetCustomersQuery", null); + return base.CreateQuery("GetCustomers", null, false, true); + } + + /// + /// Creates a new EntityContainer for this DomainContext's EntitySets. + /// + /// A new container instance. + protected override EntityContainer CreateEntityContainer() + { + return new EFComplexTypesContextEntityContainer(); + } + + /// + /// Service contract for the 'EFComplexTypesService' DomainService. + /// + [ServiceContract()] + public interface IEFComplexTypesServiceContract + { + + /// + /// Asynchronously invokes the 'GetCustomers' operation. + /// + /// Callback to invoke on completion. + /// Optional state object. + /// An IAsyncResult that can be used to monitor the request. + [HasSideEffects(false)] + [OperationContract(AsyncPattern=true, Action="http://tempuri.org/EFComplexTypesService/GetCustomers", ReplyAction="http://tempuri.org/EFComplexTypesService/GetCustomersResponse")] + IAsyncResult BeginGetCustomers(AsyncCallback callback, object asyncState); + + /// + /// Completes the asynchronous operation begun by 'BeginGetCustomers'. + /// + /// The IAsyncResult returned from 'BeginGetCustomers'. + /// The 'QueryResult' returned from the 'GetCustomers' operation. + QueryResult EndGetCustomers(IAsyncResult result); + } + + internal sealed class EFComplexTypesContextEntityContainer : EntityContainer + { + + public EFComplexTypesContextEntityContainer() + { + this.CreateEntitySet(EntitySetOperations.None); + } + } + } +} diff --git a/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/Baselines/Default/Scenarios/EF_ComplexObject.g.vb b/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/Baselines/Default/Scenarios/EF_ComplexObject.g.vb new file mode 100644 index 000000000..d9e2f6f99 --- /dev/null +++ b/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/Baselines/Default/Scenarios/EF_ComplexObject.g.vb @@ -0,0 +1,403 @@ +'------------------------------------------------------------------------------ +' +' This code was generated by a tool. +' +' Changes to this file may cause incorrect behavior and will be lost if +' the code is regenerated. +' +'------------------------------------------------------------------------------ + +Option Compare Binary +Option Infer On +Option Strict On +Option Explicit On + +Imports DataTests.Scenarios.EF.Northwind +Imports OpenRiaServices +Imports OpenRiaServices.Client +Imports OpenRiaServices.Client.Authentication +Imports System +Imports System.Collections.Generic +Imports System.ComponentModel +Imports System.ComponentModel.DataAnnotations +Imports System.Linq +Imports System.Runtime.Serialization +Imports System.ServiceModel +Imports System.Threading.Tasks + +Namespace DataTests.Scenarios.EF.Northwind + + ''' + ''' The 'AddressCT' class. + ''' + _ + Partial Public NotInheritable Class AddressCT + Inherits ComplexObject + + Private _addressLine As String + + Private _city As String + + #Region "Extensibility Method Definitions" + + ''' + ''' This method is invoked from the constructor once initialization is complete and + ''' can be used for further object setup. + ''' + Private Partial Sub OnCreated() + End Sub + Private Partial Sub OnAddressLineChanging(ByVal value As String) + End Sub + Private Partial Sub OnAddressLineChanged() + End Sub + Private Partial Sub OnCityChanging(ByVal value As String) + End Sub + Private Partial Sub OnCityChanged() + End Sub + + #End Region + + + ''' + ''' Initializes a new instance of the class. + ''' + Public Sub New() + MyBase.New + Me.OnCreated + End Sub + + ''' + ''' Gets or sets the 'AddressLine' value. + ''' + _ + Public Property AddressLine() As String + Get + Return Me._addressLine + End Get + Set + If (String.Equals(Me._addressLine, value) = false) Then + Me.OnAddressLineChanging(value) + Me.RaiseDataMemberChanging("AddressLine") + Me.ValidateProperty("AddressLine", value) + Me._addressLine = value + Me.RaiseDataMemberChanged("AddressLine") + Me.OnAddressLineChanged + End If + End Set + End Property + + ''' + ''' Gets or sets the 'City' value. + ''' + _ + Public Property City() As String + Get + Return Me._city + End Get + Set + If (String.Equals(Me._city, value) = false) Then + Me.OnCityChanging(value) + Me.RaiseDataMemberChanging("City") + Me.ValidateProperty("City", value) + Me._city = value + Me.RaiseDataMemberChanged("City") + Me.OnCityChanged + End If + End Set + End Property + End Class + + ''' + ''' The 'ContactInfoCT' class. + ''' + _ + Partial Public NotInheritable Class ContactInfoCT + Inherits ComplexObject + + Private _address As AddressCT + + Private _homePhone As String + + #Region "Extensibility Method Definitions" + + ''' + ''' This method is invoked from the constructor once initialization is complete and + ''' can be used for further object setup. + ''' + Private Partial Sub OnCreated() + End Sub + Private Partial Sub OnAddressChanging(ByVal value As AddressCT) + End Sub + Private Partial Sub OnAddressChanged() + End Sub + Private Partial Sub OnHomePhoneChanging(ByVal value As String) + End Sub + Private Partial Sub OnHomePhoneChanged() + End Sub + + #End Region + + + ''' + ''' Initializes a new instance of the class. + ''' + Public Sub New() + MyBase.New + Me.OnCreated + End Sub + + ''' + ''' Gets or sets the 'Address' value. + ''' + _ + Public Property Address() As AddressCT + Get + Return Me._address + End Get + Set + If (Object.Equals(Me._address, value) = false) Then + Me.OnAddressChanging(value) + Me.RaiseDataMemberChanging("Address") + Me.ValidateProperty("Address", value) + Me._address = value + Me.RaiseDataMemberChanged("Address") + Me.OnAddressChanged + End If + End Set + End Property + + ''' + ''' Gets or sets the 'HomePhone' value. + ''' + _ + Public Property HomePhone() As String + Get + Return Me._homePhone + End Get + Set + If (String.Equals(Me._homePhone, value) = false) Then + Me.OnHomePhoneChanging(value) + Me.RaiseDataMemberChanging("HomePhone") + Me.ValidateProperty("HomePhone", value) + Me._homePhone = value + Me.RaiseDataMemberChanged("HomePhone") + Me.OnHomePhoneChanged + End If + End Set + End Property + End Class + + ''' + ''' The 'EmployeeWithCT' entity class. + ''' + _ + Partial Public NotInheritable Class EmployeeWithCT + Inherits Entity + + Private _contactInfo As ContactInfoCT + + Private _employeeID As Integer + + #Region "Extensibility Method Definitions" + + ''' + ''' This method is invoked from the constructor once initialization is complete and + ''' can be used for further object setup. + ''' + Private Partial Sub OnCreated() + End Sub + Private Partial Sub OnContactInfoChanging(ByVal value As ContactInfoCT) + End Sub + Private Partial Sub OnContactInfoChanged() + End Sub + Private Partial Sub OnEmployeeIDChanging(ByVal value As Integer) + End Sub + Private Partial Sub OnEmployeeIDChanged() + End Sub + + #End Region + + + ''' + ''' Initializes a new instance of the class. + ''' + Public Sub New() + MyBase.New + Me.OnCreated + End Sub + + ''' + ''' Gets or sets the 'ContactInfo' value. + ''' + _ + Public Property ContactInfo() As ContactInfoCT + Get + Return Me._contactInfo + End Get + Set + If (Object.Equals(Me._contactInfo, value) = false) Then + Me.OnContactInfoChanging(value) + Me.RaiseDataMemberChanging("ContactInfo") + Me.ValidateProperty("ContactInfo", value) + Me._contactInfo = value + Me.RaiseDataMemberChanged("ContactInfo") + Me.OnContactInfoChanged + End If + End Set + End Property + + ''' + ''' Gets or sets the 'EmployeeID' value. + ''' + _ + Public Property EmployeeID() As Integer + Get + Return Me._employeeID + End Get + Set + If ((Me._employeeID = value) _ + = false) Then + Me.OnEmployeeIDChanging(value) + Me.ValidateProperty("EmployeeID", value) + Me._employeeID = value + Me.RaisePropertyChanged("EmployeeID") + Me.OnEmployeeIDChanged + End If + End Set + End Property + + ''' + ''' Computes a value from the key fields that uniquely identifies this entity instance. + ''' + ''' An object instance that uniquely identifies this entity instance. + Public Overrides Function GetIdentity() As Object + Return Me._employeeID + End Function + End Class +End Namespace + +Namespace OpenRiaServices.Tools.Test + + ''' + ''' The DomainContext corresponding to the 'EFComplexTypesService' DomainService. + ''' + Partial Public NotInheritable Class EFComplexTypesContext + Inherits DomainContext + + #Region "Extensibility Method Definitions" + + ''' + ''' This method is invoked from the constructor once initialization is complete and + ''' can be used for further object setup. + ''' + Private Partial Sub OnCreated() + End Sub + + #End Region + + + ''' + ''' Initializes a new instance of the class. + ''' + Public Sub New() + Me.New(New Uri("OpenRiaServices-Tools-Test-EFComplexTypesService.svc", UriKind.Relative)) + End Sub + + ''' + ''' Initializes a new instance of the class with the specified service URI. + ''' + ''' The EFComplexTypesService service URI. + Public Sub New(ByVal serviceUri As Uri) + Me.New(DomainContext.CreateDomainClient(GetType(IEFComplexTypesServiceContract), serviceUri, false)) + End Sub + + ''' + ''' Initializes a new instance of the class with the specified . + ''' + ''' The DomainClient instance to use for this DomainContext. + Public Sub New(ByVal domainClient As DomainClient) + MyBase.New(domainClient) + Me.OnCreated + End Sub + + ''' + ''' Gets the set of entity instances that have been loaded into this instance. + ''' + Public ReadOnly Property EmployeeWithCTs() As EntitySet(Of EmployeeWithCT) + Get + Return MyBase.EntityContainer.GetEntitySet(Of EmployeeWithCT) + End Get + End Property + + ''' + ''' Gets an EntityQuery instance that can be used to load entity instances using the 'GetCustomers' query. + ''' + ''' An EntityQuery that can be loaded to retrieve entity instances. + Public Function GetCustomersQuery() As EntityQuery(Of EmployeeWithCT) + Me.ValidateMethod("GetCustomersQuery", Nothing) + Return MyBase.CreateQuery(Of EmployeeWithCT)("GetCustomers", Nothing, false, true) + End Function + + ''' + ''' Creates a new EntityContainer for this DomainContext's EntitySets. + ''' + ''' A new container instance. + Protected Overrides Function CreateEntityContainer() As EntityContainer + Return New EFComplexTypesContextEntityContainer() + End Function + + ''' + ''' Service contract for the 'EFComplexTypesService' DomainService. + ''' + _ + Public Interface IEFComplexTypesServiceContract + + ''' + ''' Asynchronously invokes the 'GetCustomers' operation. + ''' + ''' Callback to invoke on completion. + ''' Optional state object. + ''' An IAsyncResult that can be used to monitor the request. + _ + Function BeginGetCustomers(ByVal callback As AsyncCallback, ByVal asyncState As Object) As IAsyncResult + + ''' + ''' Completes the asynchronous operation begun by 'BeginGetCustomers'. + ''' + ''' The IAsyncResult returned from 'BeginGetCustomers'. + ''' The 'QueryResult' returned from the 'GetCustomers' operation. + Function EndGetCustomers(ByVal result As IAsyncResult) As QueryResult(Of EmployeeWithCT) + End Interface + + Friend NotInheritable Class EFComplexTypesContextEntityContainer + Inherits EntityContainer + + Public Sub New() + MyBase.New + Me.CreateEntitySet(Of EmployeeWithCT)(EntitySetOperations.None) + End Sub + End Class + End Class +End Namespace diff --git a/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/OpenRiaServices.Common.DomainServices.Test.csproj b/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/OpenRiaServices.Common.DomainServices.Test.csproj index 27c5f0416..38f7ba012 100644 --- a/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/OpenRiaServices.Common.DomainServices.Test.csproj +++ b/src/Test/Desktop/OpenRiaServices.Common.DomainServices.Test/OpenRiaServices.Common.DomainServices.Test.csproj @@ -58,6 +58,18 @@ Always + + Always + + + Always + + + Always + + + Always + Always @@ -597,6 +609,8 @@ + + diff --git a/src/Test/WebsiteFullTrust/WebsiteFullTrust.csproj b/src/Test/WebsiteFullTrust/WebsiteFullTrust.csproj index 8cd153988..c73e8001f 100644 --- a/src/Test/WebsiteFullTrust/WebsiteFullTrust.csproj +++ b/src/Test/WebsiteFullTrust/WebsiteFullTrust.csproj @@ -113,6 +113,8 @@ {b8d39090-3b76-41bb-a139-956e42619e91} OpenRiaServices.Server.EntityFrameworkCore + + TargetFramework=netstandard2.0 {B33BF27F-7DF7-46FF-A1DA-F12A873E124F}