Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EntityAssociationAttribute Step2 #513

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 28 additions & 7 deletions src/OpenRiaServices.Client/Framework/EntityAssociationAttribute.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
using System;
using System.Collections.Generic;

#nullable enable
#pragma warning disable CS3015 // Type has no accessible constructors which use only CLS-compliant types

namespace OpenRiaServices
namespace System.ComponentModel.DataAnnotations
{
/// <summary>
/// Used to mark an Entity member as an association
/// Used to mark an Entity member as an association.
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]

public sealed class EntityAssociationAttribute : Attribute
#pragma warning restore CS3015 // Type has no accessible constructors which use only CLS-compliant types
{
/// <summary>
/// Full form of constructor
/// Create an instance that defines an association between two entities, using any number of key members.
/// </summary>
/// <param name="name">The name of the association. For bi-directional associations,
/// the name must be the same on both sides of the association</param>
Expand All @@ -26,14 +26,35 @@ public EntityAssociationAttribute(string name, string[] thisKey, string[] otherK
ThisKeyMembers = thisKey ?? throw new ArgumentNullException(nameof(thisKey));
OtherKeyMembers = otherKey ?? throw new ArgumentNullException(nameof(otherKey));

if (name .Length == 0)
if (name.Length == 0)
throw new ArgumentException("Name cannot be empty", nameof(name));
if (thisKey.Length == 0)
throw new ArgumentException("ThisKey cannot be empty", nameof(thisKey));
if (otherKey.Length == 0)
throw new ArgumentException("OtherKey cannot be empty", nameof(otherKey));
}

/// <summary>
/// Create an instance that defines an association using a single key member.
/// </summary>
/// <param name="name">The name of the association. For bi-directional associations,
/// the name must be the same on both sides of the association</param>
/// <param name="thisKey">A single property name of the key value on this side of the association</param>
/// <param name="otherKey">A single property name of the key value on the other side of the association</param>
public EntityAssociationAttribute(string name, string thisKey, string otherKey)
{
if (string.IsNullOrEmpty(name))
throw new ArgumentException("Name cannot be empty", nameof(name));
if (string.IsNullOrEmpty(thisKey))
throw new ArgumentException("ThisKey cannot be empty", nameof(thisKey));
if (string.IsNullOrEmpty(otherKey))
throw new ArgumentException("OtherKey cannot be empty", nameof(otherKey));

Name = name;
ThisKeyMembers = [thisKey];
OtherKeyMembers = [otherKey];
}

/// <summary>
/// Gets the name of the association. For bi-directional associations, the name must
/// be the same on both sides of the association
Expand All @@ -49,12 +70,12 @@ public EntityAssociationAttribute(string name, string[] thisKey, string[] otherK
/// <summary>
/// Gets the collection of individual key members specified in the ThisKey string.
/// </summary>
public IReadOnlyCollection<string> ThisKeyMembers { get; }
public IReadOnlyList<string> ThisKeyMembers { get; }

/// <summary>
/// Gets the collection of individual key members specified in the OtherKey string.
/// </summary>
public IReadOnlyCollection<string> OtherKeyMembers { get; }
public IReadOnlyList<string> OtherKeyMembers { get; }

/// <summary>
/// Gets or sets the key value on this side of the association
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<NoWarn>108</NoWarn>
<TargetFrameworks>net472;net6.0-windows;net8.0-windows</TargetFrameworks>
<Version>1.0.0.0</Version>
<UseWPF>true</UseWPF>
<DefineConstants>$(DefineConstants);HAS_COLLECTIONVIEW</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition=" '$(TargetFramework)' != 'net472'">
<!-- Disable obsolete warning (primarily AssociationAttribute) -->
<NoWarn>$(NoWarn);CS0618</NoWarn>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.3.1" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
<PropertyGroup>
<TargetFrameworks>net472</TargetFrameworks>
<DefineConstants>TRACE;DEBUG;VBTests</DefineConstants>
<NoWarn>108</NoWarn>
<RootNamespace>OpenRiaServices.Client.Test</RootNamespace>
</PropertyGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<NoWarn>618</NoWarn>
<RootNamespace>CodeFirstModels</RootNamespace>
<AssemblyName>CodeFirstModels</AssemblyName>
<TargetFrameworks>net472;net6.0</TargetFrameworks>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,36 +16,48 @@ internal class EntityAssociationAttributeBuilder : ICustomAttributeBuilder
/// </summary>
public AttributeDeclaration GetAttributeDeclaration(Attribute attribute)
{
AttributeDeclaration attributeDeclaration = new AttributeDeclaration(typeof(EntityAssociationAttribute));
string name;
string[] thisKey, otherKey;
bool isForeignKey;

if (attribute is EntityAssociationAttribute entityAssociation)
{
attributeDeclaration.ConstructorArguments.Add(entityAssociation.Name);
attributeDeclaration.ConstructorArguments.Add((string[])entityAssociation.ThisKeyMembers);
attributeDeclaration.ConstructorArguments.Add((string[])entityAssociation.OtherKeyMembers);

if (entityAssociation.IsForeignKey)
{
attributeDeclaration.NamedParameters.Add(nameof(EntityAssociationAttribute.IsForeignKey), true);
}
name = entityAssociation.Name;
thisKey = (string[])entityAssociation.ThisKeyMembers;
otherKey = (string[])entityAssociation.OtherKeyMembers;
isForeignKey = entityAssociation.IsForeignKey;
}
else if (attribute is AssociationAttribute associationAttribute)
{
// [EntityAssociation( {true|false} )]
attributeDeclaration.ConstructorArguments.Add(associationAttribute.Name);
attributeDeclaration.ConstructorArguments.Add(associationAttribute.ThisKeyMembers.ToArray());
attributeDeclaration.ConstructorArguments.Add(associationAttribute.OtherKeyMembers.ToArray());

if (associationAttribute.IsForeignKey)
{
attributeDeclaration.NamedParameters.Add(nameof(EntityAssociationAttribute.IsForeignKey), true);
}
name = associationAttribute.Name;
thisKey = associationAttribute.ThisKeyMembers.ToArray();
otherKey = associationAttribute.OtherKeyMembers.ToArray();
isForeignKey = associationAttribute.IsForeignKey;
}
else
{
return null;
}

// Generate the attribute declaration
// If there is only a single key member, we use string based constructor
AttributeDeclaration attributeDeclaration = new AttributeDeclaration(typeof(EntityAssociationAttribute));
attributeDeclaration.ConstructorArguments.Add(name);
if (thisKey.Length == 1 && otherKey.Length == 1)
{
attributeDeclaration.ConstructorArguments.Add(thisKey[0]);
attributeDeclaration.ConstructorArguments.Add(otherKey[0]);
}
else
{
attributeDeclaration.ConstructorArguments.Add(thisKey);
attributeDeclaration.ConstructorArguments.Add(otherKey);
}

if (isForeignKey)
{
attributeDeclaration.NamedParameters.Add(nameof(EntityAssociationAttribute.IsForeignKey), true);
}
return attributeDeclaration;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public void CodeGen_External_Entity_EFtoPOCO()
TestHelper.AssertGeneratedCodeContains(
generatedCode,
"private EntityRef<global::DataTests.Scenarios.EF.Northwind.PersonalDetails> _personalDetails_MarkedAsExternal;",
"[EntityAssociation(\"Employee_PersonalDetails\", new string[] { \"EmployeeID\"}, new string[] { \"UniqueID\"}, IsForeignKey=true)] [ExternalReference()]",
"[EntityAssociation(\"Employee_PersonalDetails\", \"EmployeeID\", \"UniqueID\", IsForeignKey=true)] [ExternalReference()]",
"public global::DataTests.Scenarios.EF.Northwind.PersonalDetails PersonalDetails_MarkedAsExternal",
"private bool FilterPersonalDetails_MarkedAsExternal(global::DataTests.Scenarios.EF.Northwind.PersonalDetails entity)");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1750,9 +1750,7 @@ public string Name
/// <summary>
/// Gets or sets the associated <see cref="State"/> entity.
/// </summary>
[EntityAssociation("State_County", new string[] {
"StateName"}, new string[] {
"Name"}, IsForeignKey=true)]
[EntityAssociation("State_County", "StateName", "Name", IsForeignKey=true)]
public State State
{
get
Expand Down Expand Up @@ -1930,9 +1928,7 @@ public State()
/// </summary>
[CustomValidation(typeof(CountiesValidator), "AreCountiesValid")]
[Editable(false)]
[EntityAssociation("State_County", new string[] {
"Name"}, new string[] {
"StateName"})]
[EntityAssociation("State_County", "Name", "StateName")]
[ReadOnly(true)]
public EntityCollection<County> Counties
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1628,7 +1628,7 @@ Namespace Cities
''' <summary>
''' Gets or sets the associated <see cref="State"/> entity.
''' </summary>
<EntityAssociation("State_County", New String() {"StateName"}, New String() {"Name"}, IsForeignKey:=true)> _
<EntityAssociation("State_County", "StateName", "Name", IsForeignKey:=true)> _
Public Property State() As State
Get
If (Me._state Is Nothing) Then
Expand Down Expand Up @@ -1793,7 +1793,7 @@ Namespace Cities
''' </summary>
<CustomValidation(GetType(CountiesValidator), "AreCountiesValid"), _
Editable(false), _
EntityAssociation("State_County", New String() {"Name"}, New String() {"StateName"}), _
EntityAssociation("State_County", "Name", "StateName"), _
[ReadOnly](true)> _
Public ReadOnly Property Counties() As EntityCollection(Of County)
Get
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -295,9 +295,7 @@ public string LoginID
/// <summary>
/// Gets or sets the associated <see cref="Employee"/> entity.
/// </summary>
[EntityAssociation("Employee_Employee", new string[] {
"ManagerID"}, new string[] {
"EmployeeID"}, IsForeignKey=true)]
[EntityAssociation("Employee_Employee", "ManagerID", "EmployeeID", IsForeignKey=true)]
public Employee Manager
{
get
Expand Down Expand Up @@ -441,9 +439,7 @@ public string NationalIDNumber
/// <summary>
/// Gets the collection of associated <see cref="PurchaseOrder"/> entity instances.
/// </summary>
[EntityAssociation("Employee_PurchaseOrder", new string[] {
"EmployeeID"}, new string[] {
"EmployeeID"})]
[EntityAssociation("Employee_PurchaseOrder", "EmployeeID", "EmployeeID")]
public EntityCollection<PurchaseOrder> PurchaseOrders
{
get
Expand All @@ -459,9 +455,7 @@ public EntityCollection<PurchaseOrder> PurchaseOrders
/// <summary>
/// Gets the collection of associated <see cref="Employee"/> entity instances.
/// </summary>
[EntityAssociation("Employee_Employee", new string[] {
"EmployeeID"}, new string[] {
"ManagerID"})]
[EntityAssociation("Employee_Employee", "EmployeeID", "ManagerID")]
public EntityCollection<Employee> Reports
{
get
Expand Down Expand Up @@ -1265,9 +1259,7 @@ public Nullable<int> ProductSubcategoryID
/// <summary>
/// Gets the collection of associated <see cref="PurchaseOrderDetail"/> entity instances.
/// </summary>
[EntityAssociation("Product_PurchaseOrderDetail", new string[] {
"ProductID"}, new string[] {
"ProductID"})]
[EntityAssociation("Product_PurchaseOrderDetail", "ProductID", "ProductID")]
public EntityCollection<PurchaseOrderDetail> PurchaseOrderDetails
{
get
Expand Down Expand Up @@ -1637,9 +1629,7 @@ public PurchaseOrder()
/// <summary>
/// Gets or sets the associated <see cref="Employee"/> entity.
/// </summary>
[EntityAssociation("Employee_PurchaseOrder", new string[] {
"EmployeeID"}, new string[] {
"EmployeeID"}, IsForeignKey=true)]
[EntityAssociation("Employee_PurchaseOrder", "EmployeeID", "EmployeeID", IsForeignKey=true)]
public Employee Employee
{
get
Expand Down Expand Up @@ -1779,9 +1769,7 @@ public DateTime OrderDate
/// <summary>
/// Gets the collection of associated <see cref="PurchaseOrderDetail"/> entity instances.
/// </summary>
[EntityAssociation("PurchaseOrder_PurchaseOrderDetail", new string[] {
"PurchaseOrderID"}, new string[] {
"PurchaseOrderID"})]
[EntityAssociation("PurchaseOrder_PurchaseOrderDetail", "PurchaseOrderID", "PurchaseOrderID")]
public EntityCollection<PurchaseOrderDetail> PurchaseOrderDetails
{
get
Expand Down Expand Up @@ -2217,9 +2205,7 @@ public short OrderQty
/// <summary>
/// Gets or sets the associated <see cref="Product"/> entity.
/// </summary>
[EntityAssociation("Product_PurchaseOrderDetail", new string[] {
"ProductID"}, new string[] {
"ProductID"}, IsForeignKey=true)]
[EntityAssociation("Product_PurchaseOrderDetail", "ProductID", "ProductID", IsForeignKey=true)]
public Product Product
{
get
Expand Down Expand Up @@ -2287,9 +2273,7 @@ public int ProductID
/// <summary>
/// Gets or sets the associated <see cref="PurchaseOrder"/> entity.
/// </summary>
[EntityAssociation("PurchaseOrder_PurchaseOrderDetail", new string[] {
"PurchaseOrderID"}, new string[] {
"PurchaseOrderID"}, IsForeignKey=true)]
[EntityAssociation("PurchaseOrder_PurchaseOrderDetail", "PurchaseOrderID", "PurchaseOrderID", IsForeignKey=true)]
public PurchaseOrder PurchaseOrder
{
get
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ Namespace AdventureWorksModel
''' <summary>
''' Gets or sets the associated <see cref="Employee"/> entity.
''' </summary>
<EntityAssociation("Employee_Employee", New String() {"ManagerID"}, New String() {"EmployeeID"}, IsForeignKey:=true)> _
<EntityAssociation("Employee_Employee", "ManagerID", "EmployeeID", IsForeignKey:=true)> _
Public Property Manager() As Employee
Get
If (Me._manager Is Nothing) Then
Expand Down Expand Up @@ -430,7 +430,7 @@ Namespace AdventureWorksModel
''' <summary>
''' Gets the collection of associated <see cref="PurchaseOrder"/> entity instances.
''' </summary>
<EntityAssociation("Employee_PurchaseOrder", New String() {"EmployeeID"}, New String() {"EmployeeID"})> _
<EntityAssociation("Employee_PurchaseOrder", "EmployeeID", "EmployeeID")> _
Public ReadOnly Property PurchaseOrders() As EntityCollection(Of PurchaseOrder)
Get
If (Me._purchaseOrders Is Nothing) Then
Expand All @@ -443,7 +443,7 @@ Namespace AdventureWorksModel
''' <summary>
''' Gets the collection of associated <see cref="Employee"/> entity instances.
''' </summary>
<EntityAssociation("Employee_Employee", New String() {"EmployeeID"}, New String() {"ManagerID"})> _
<EntityAssociation("Employee_Employee", "EmployeeID", "ManagerID")> _
Public ReadOnly Property Reports() As EntityCollection(Of Employee)
Get
If (Me._reports Is Nothing) Then
Expand Down Expand Up @@ -1213,7 +1213,7 @@ Namespace AdventureWorksModel
''' <summary>
''' Gets the collection of associated <see cref="PurchaseOrderDetail"/> entity instances.
''' </summary>
<EntityAssociation("Product_PurchaseOrderDetail", New String() {"ProductID"}, New String() {"ProductID"})> _
<EntityAssociation("Product_PurchaseOrderDetail", "ProductID", "ProductID")> _
Public ReadOnly Property PurchaseOrderDetails() As EntityCollection(Of PurchaseOrderDetail)
Get
If (Me._purchaseOrderDetails Is Nothing) Then
Expand Down Expand Up @@ -1567,7 +1567,7 @@ Namespace AdventureWorksModel
''' <summary>
''' Gets or sets the associated <see cref="Employee"/> entity.
''' </summary>
<EntityAssociation("Employee_PurchaseOrder", New String() {"EmployeeID"}, New String() {"EmployeeID"}, IsForeignKey:=true)> _
<EntityAssociation("Employee_PurchaseOrder", "EmployeeID", "EmployeeID", IsForeignKey:=true)> _
Public Property Employee() As Employee
Get
If (Me._employee Is Nothing) Then
Expand Down Expand Up @@ -1685,7 +1685,7 @@ Namespace AdventureWorksModel
''' <summary>
''' Gets the collection of associated <see cref="PurchaseOrderDetail"/> entity instances.
''' </summary>
<EntityAssociation("PurchaseOrder_PurchaseOrderDetail", New String() {"PurchaseOrderID"}, New String() {"PurchaseOrderID"})> _
<EntityAssociation("PurchaseOrder_PurchaseOrderDetail", "PurchaseOrderID", "PurchaseOrderID")> _
Public ReadOnly Property PurchaseOrderDetails() As EntityCollection(Of PurchaseOrderDetail)
Get
If (Me._purchaseOrderDetails Is Nothing) Then
Expand Down Expand Up @@ -2096,7 +2096,7 @@ Namespace AdventureWorksModel
''' <summary>
''' Gets or sets the associated <see cref="Product"/> entity.
''' </summary>
<EntityAssociation("Product_PurchaseOrderDetail", New String() {"ProductID"}, New String() {"ProductID"}, IsForeignKey:=true)> _
<EntityAssociation("Product_PurchaseOrderDetail", "ProductID", "ProductID", IsForeignKey:=true)> _
Public Property Product() As Product
Get
If (Me._product Is Nothing) Then
Expand Down Expand Up @@ -2151,7 +2151,7 @@ Namespace AdventureWorksModel
''' <summary>
''' Gets or sets the associated <see cref="PurchaseOrder"/> entity.
''' </summary>
<EntityAssociation("PurchaseOrder_PurchaseOrderDetail", New String() {"PurchaseOrderID"}, New String() {"PurchaseOrderID"}, IsForeignKey:=true)> _
<EntityAssociation("PurchaseOrder_PurchaseOrderDetail", "PurchaseOrderID", "PurchaseOrderID", IsForeignKey:=true)> _
Public Property PurchaseOrder() As PurchaseOrder
Get
If (Me._purchaseOrder Is Nothing) Then
Expand Down
Loading
Loading