Skip to content

Commit b3b8913

Browse files
committed
Minor updates
- Entity loading methods now honor ColumnAttribute settings. - Added support for ParameterNameAttribute. - Updated conversion utility to use member name attribute if property name attribute is missing.
1 parent 339affb commit b3b8913

File tree

11 files changed

+168
-21
lines changed

11 files changed

+168
-21
lines changed

DbmlToEntityFrameworkConverter/DbmlToEntityFrameworkConverter.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
<Title>DBML to Entity Framework Converter</Title>
99
<Copyright>Copyright (c) 2024, Eric Woodruff, All Rights Reserved</Copyright>
1010
<NeutralLanguage>en</NeutralLanguage>
11-
<Version>2025.9.5.0</Version>
12-
<FileVersion>2025.9.5.0</FileVersion>
11+
<Version>2025.10.17.0</Version>
12+
<FileVersion>2025.10.17.0</FileVersion>
1313
<Description>This utility is used to convert LINQ to SQL DBML file definitions to rough equivalents of their Entity Framework counterparts.</Description>
1414
<SignAssembly>true</SignAssembly>
1515
<AssemblyOriginatorKeyFile>..\EntityFrameworkUtils.snk</AssemblyOriginatorKeyFile>

DbmlToEntityFrameworkConverter/PropertyInfo.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// System : EWSoftware Entity Framework Utilities
33
// File : PropertyInfo.cs
44
// Author : Eric Woodruff
5-
// Updated : 12/16/2024
5+
// Updated : 10/02/2025
66
//
77
// This file contains a class used to contain entity type property information from a DBML file
88
//
@@ -85,6 +85,10 @@ internal sealed class PropertyInfo
8585
public PropertyInfo(XElement propertyInfo)
8686
{
8787
this.PropertyName = propertyInfo.Attribute("Name")!.Value;
88+
89+
if(String.IsNullOrWhiteSpace(this.PropertyName))
90+
this.PropertyName = propertyInfo.Attribute("Member")?.Value ?? "ColumnNameNotSpecified";
91+
8892
this.BackingFieldName = $"_{Char.ToLowerInvariant(this.PropertyName[0])}{this.PropertyName[1..]}";
8993
this.PropertyType = PropertyTypes[propertyInfo.Attribute("Type")!.Value];
9094
this.IsPrimaryKey = (bool?)propertyInfo.Attribute("IsPrimaryKey") ?? false;

EFUtilsDocs/Content/EntityStoredProcAttributes.aml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,30 @@ public sealed class StateCode
4444
</content>
4545
</section>
4646

47+
<section address="ParameterName">
48+
<title>ParameterNameAttribute</title>
49+
<content>
50+
<para>Similar to the <codeInline>ColumnAttribute</codeInline>, a <codeInline>ParameterNameAttribute</codeInline>
51+
can be applied to a property to specify the stored procedure parameter name to use for it. If specified along
52+
with a <codeInline>ColumnAttribute</codeInline>, the <codeInline>ParameterNameAttribute</codeInline> will take
53+
precedence. This is useful when the name in the result set differs from the parameter name as shown in the
54+
example below.</para>
55+
56+
<code language="csharp">
57+
public sealed class CaseInformation
58+
{
59+
// The name in the result set contains a space. For the parameter name,
60+
// it uses an underscore.
61+
[Column("Case Number"), ParameterName("Case_Number")]
62+
public string CaseNumber { get; set; }
63+
.
64+
.
65+
.
66+
}
67+
</code>
68+
</content>
69+
</section>
70+
4771
<section address="Ignore">
4872
<title>IgnoreAttribute</title>
4973
<content>

EFUtilsDocs/Content/VersionHistory/VersionHistory.aml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ the life of the project.</para>
1111
<para>Select a version below to see a description of its changes.</para>
1212

1313
<list class="bullet">
14+
<listItem>
15+
<para>
16+
<link xlink:href="83034672-919d-478b-9dcb-50dec455ef61" />
17+
</para>
18+
</listItem>
19+
1420
<listItem>
1521
<para>
1622
<link xlink:href="58821c50-69c8-4b6b-be71-b88953973a37" />
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<topic id="83034672-919d-478b-9dcb-50dec455ef61" revisionNumber="1">
3+
<developerConceptualDocument xmlns="http://ddue.schemas.microsoft.com/authoring/2003/5" xmlns:xlink="http://www.w3.org/1999/xlink">
4+
<introduction>
5+
<para>Changes made in this release:</para>
6+
</introduction>
7+
8+
<section>
9+
<content>
10+
<list class="bullet">
11+
<listItem>
12+
<para>All entity loading extension methods will now honor <codeInline>ColumnAttribute</codeInline>
13+
settings on entity properties to ensure proper mapping of result set columns to entity properties.</para>
14+
</listItem>
15+
16+
<listItem>
17+
<para>Added <codeEntityReference qualifyHint="false">T:EWSoftware.EntityFramework.DataAnnotations.ParameterNameAttribute</codeEntityReference>
18+
so that a stored procedure parameter name can be applied to entity properties and stored procedure method
19+
parameters to define the parameter name if it differs from the property/method parameter name.</para>
20+
</listItem>
21+
22+
<listItem>
23+
<para>Updated the conversion utility to use the member name attribute value if a property name value
24+
is missing.</para>
25+
</listItem>
26+
</list>
27+
28+
</content>
29+
</section>
30+
31+
<relatedTopics>
32+
<link xlink:href="73c00da4-99f1-47c5-aaf3-0bc31fcc8066" />
33+
</relatedTopics>
34+
35+
</developerConceptualDocument>
36+
</topic>

EFUtilsDocs/ContentLayout.content

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
<Topic id="f818ea4c-f1c6-4bc0-b7f1-373bde857dd1" visible="True" title="Result Set and Parameter Extension Methods" />
1010
<Topic id="9bfd97fc-06aa-49a4-a663-df34f92ab78a" visible="True" title="DBML to Entity Framework Converter" />
1111
<Topic id="73c00da4-99f1-47c5-aaf3-0bc31fcc8066" visible="True" isExpanded="true" title="Version History">
12-
<Topic id="58821c50-69c8-4b6b-be71-b88953973a37" visible="True" isSelected="true" title="Version 2025.9.5.0" />
12+
<Topic id="83034672-919d-478b-9dcb-50dec455ef61" visible="True" isSelected="true" title="Version 2025.10.17.0" />
13+
<Topic id="58821c50-69c8-4b6b-be71-b88953973a37" visible="True" title="Version 2025.9.5.0" />
1314
<Topic id="3e733635-1d08-4db1-909a-1acc87778c68" visible="True" title="Version 2025.8.22.0" />
1415
<Topic id="5bca4196-25c0-47b3-a8a7-2957a30cc71f" visible="True" title="Version 2025.7.14.0" />
1516
<Topic id="e0b384f4-919c-4b0c-a6ad-f6e8f05dfdb9" visible="True" title="Version 2025.6.14.0" />

EFUtilsDocs/EFUtilsDocs.shfbproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
<BuildAssemblerVerbosity>OnlyWarningsAndErrors</BuildAssemblerVerbosity>
5757
<SaveComponentCacheCapacity>100</SaveComponentCacheCapacity>
5858
<HelpTitle>EWSofware Entity Framework Utilities Library Documentation</HelpTitle>
59-
<HelpFileVersion>2025.9.5.0</HelpFileVersion>
59+
<HelpFileVersion>2025.10.17.0</HelpFileVersion>
6060
<NamingMethod>Guid</NamingMethod>
6161
<ContentPlacement>AboveNamespaces</ContentPlacement>
6262
<RootNamespaceContainer>False</RootNamespaceContainer>
@@ -155,6 +155,7 @@
155155
<None Include="Content\StoredProcedureMethods.aml" />
156156
<None Include="Content\VersionHistory\v2024.12.29.0.aml" />
157157
<None Include="Content\VersionHistory\v2025.1.16.0.aml" />
158+
<None Include="Content\VersionHistory\v2025.10.17.0.aml" />
158159
<None Include="Content\VersionHistory\v2025.2.15.0.aml" />
159160
<None Include="Content\VersionHistory\v2025.3.17.0.aml" />
160161
<None Include="Content\VersionHistory\v2025.6.14.0.aml" />
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//===============================================================================================================
2+
// System : EWSoftware Entity Framework Utilities
3+
// File : ParameterNameAttribute.cs
4+
// Author : Eric Woodruff
5+
// Updated : 10/17/2025
6+
//
7+
// This file contains an attribute used to define a stored procedure parameter name on an entity property
8+
//
9+
// Date Who Comments
10+
// ==============================================================================================================
11+
// 10/17/2024 EFW Created the code
12+
//===============================================================================================================
13+
14+
namespace EWSoftware.EntityFramework.DataAnnotations
15+
{
16+
/// <summary>
17+
/// This attribute is used to define a stored procedure parameter name that will be used for an entity
18+
/// property.
19+
/// </summary>
20+
/// <remarks>If specified, this will take precedence over a <see cref="ColumnAttribute"/> allowing for
21+
/// a different column name and stored procedure parameter name.</remarks>
22+
/// <example>
23+
/// <code language="cs">
24+
/// public sealed class CaseInformation
25+
/// {
26+
/// // The name in the result set contains a space. For the parameter
27+
/// // name, it uses an underscore.
28+
/// [Column("Case Number"), ParameterName("Case_Number")]
29+
/// public string CaseNumber { get; set; }
30+
/// .
31+
/// .
32+
/// .
33+
/// }
34+
/// </code>
35+
/// </example>
36+
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
37+
public sealed class ParameterNameAttribute : Attribute
38+
{
39+
#region Properties
40+
//=====================================================================
41+
42+
/// <summary>
43+
/// This read-only property returns the parameter name that will used
44+
/// </summary>
45+
public string Name { get; }
46+
47+
#endregion
48+
49+
#region Constructor
50+
//=====================================================================
51+
52+
/// <summary>
53+
/// Initialize a new instance of the attribute using the given parameter name
54+
/// </summary>
55+
/// <param name="name">The parameter name to use</param>
56+
public ParameterNameAttribute(string name)
57+
{
58+
this.Name = name ?? throw new ArgumentNullException(nameof(name));
59+
}
60+
#endregion
61+
}
62+
}

Source/DataAnnotations/ParameterNamePrefixAttribute.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//===============================================================================================================
22
// System : EWSoftware Entity Framework Utilities
3-
// File : ParamaterNamePrefixAttribute.cs
3+
// File : ParameterNamePrefixAttribute.cs
44
// Author : Eric Woodruff
55
// Updated : 11/25/2024
66
//

Source/DatabaseExtensions.cs

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// System : EWSoftware Entity Framework Utilities
33
// File : DatabaseExtensions.cs
44
// Author : Eric Woodruff
5-
// Updated : 09/05/2025
5+
// Updated : 10/17/2025
66
//
77
// This file contains a class that contains extension methods for database objects
88
//
@@ -128,6 +128,15 @@ private static (DbConnection connection, DbCommand command, Dictionary<string, P
128128
var connection = dataContext.Database.GetDbConnection();
129129
var command = connection.CreateCommand();
130130

131+
// If any properties have a column name attribute, add an entry for the alias
132+
foreach(var p in properties.Values.ToList())
133+
{
134+
var cn = p.GetCustomAttribute<ColumnAttribute>();
135+
136+
if(cn != null)
137+
properties[cn.Name!] = p;
138+
}
139+
131140
command.CommandType = CommandType.StoredProcedure;
132141
command.CommandText = CreateStoredProcedureName(dataContext, storedProcName!);
133142

@@ -150,8 +159,9 @@ private static (DbConnection connection, DbCommand command, Dictionary<string, P
150159
if(!properties.TryGetValue(key, out var p))
151160
throw new InvalidOperationException($"The key property {key} was not found on the entity");
152161

153-
// If the property has a column attribute, use the name from it instead
154-
var columnName = p.GetCustomAttribute<ColumnAttribute>();
162+
// If the property has a parameter name or column attribute, use the name from it instead
163+
string? columnName = p.GetCustomAttribute<ParameterNameAttribute>()?.Name ??
164+
p.GetCustomAttribute<ColumnAttribute>()?.Name;
155165

156166
object? value = parameters[paramIdx++];
157167

@@ -171,7 +181,7 @@ private static (DbConnection connection, DbCommand command, Dictionary<string, P
171181

172182
// If the parameter value is null, use DBNull.Value to send a NULL to the database rather than
173183
// using any default value assigned to the parameter.
174-
var param = new SqlParameter($"@{parameterNamePrefix}{columnName?.Name ?? key}",
184+
var param = new SqlParameter($"@{parameterNamePrefix}{columnName ?? key}",
175185
value ?? DBNull.Value);
176186
param.SetParameterType(p.PropertyType);
177187
command.Parameters.Add(param);
@@ -244,13 +254,14 @@ private static (DbConnection connection, DbCommand command,
244254

245255
if((forInsert && !(ignored?.ForInsert ?? false)) || (!forInsert && !(ignored?.ForUpdate ?? false)))
246256
{
247-
// If the property has a column attribute, use the name from it instead
248-
var columnName = p.GetCustomAttribute<ColumnAttribute>();
257+
// If the property has a parameter name or column attribute, use the name from it instead
258+
string? columnName = p.GetCustomAttribute<ParameterNameAttribute>()?.Name ??
259+
p.GetCustomAttribute<ColumnAttribute>()?.Name;
249260
var timestamp = p.GetCustomAttribute<TimestampAttribute>();
250261

251262
// If the parameter value is null, use DBNull.Value to send a NULL to the database rather than
252263
// using any default value assigned to the parameter.
253-
var param = new SqlParameter($"@{parameterNamePrefix}{columnName?.Name ?? p.Name}",
264+
var param = new SqlParameter($"@{parameterNamePrefix}{columnName ?? p.Name}",
254265
p.GetValue(entity) ?? DBNull.Value);
255266
param.SetParameterType(p.PropertyType);
256267

@@ -310,12 +321,13 @@ private static (DbConnection connection, DbCommand command, bool neverTrack)
310321
if(!properties.TryGetValue(key, out var p))
311322
throw new InvalidOperationException($"The key property {key} was not found on the entity");
312323

313-
// If the property has a column attribute, use the name from it instead
314-
var columnName = p.GetCustomAttribute<ColumnAttribute>();
324+
// If the property has a parameter name or column attribute, use the name from it instead
325+
string? columnName = p.GetCustomAttribute<ParameterNameAttribute>()?.Name ??
326+
p.GetCustomAttribute<ColumnAttribute>()?.Name;
315327

316328
// If the property value is null, use DBNull.Value to send a NULL to the database rather than
317329
// using any default value assigned to the parameter.
318-
var param = new SqlParameter($"@{parameterNamePrefix}{columnName?.Name ?? key}",
330+
var param = new SqlParameter($"@{parameterNamePrefix}{columnName ?? key}",
319331
p.GetValue(entity) ?? DBNull.Value);
320332
param.SetParameterType(p.PropertyType);
321333
command.Parameters.Add(param);
@@ -522,8 +534,9 @@ private static async Task<int> InsertUpdateEntityInternalAsync<TEntity>(DbContex
522534
{
523535
var mp = methodParams[idx];
524536

525-
// If the parameter has a column attribute, use the name from it instead
526-
var columnName = mp.GetCustomAttribute<ColumnAttribute>();
537+
// If the parameter has a parameter name or column attribute, use the name from it instead
538+
string? columnName = mp.GetCustomAttribute<ParameterNameAttribute>()?.Name ??
539+
mp.GetCustomAttribute<ColumnAttribute>()?.Name;
527540

528541
object? value = parameters[idx];
529542
var paramType = mp.ParameterType.IsByRef ? mp.ParameterType.GetElementType()! : mp.ParameterType;
@@ -544,7 +557,7 @@ private static async Task<int> InsertUpdateEntityInternalAsync<TEntity>(DbContex
544557

545558
// If the parameter value is null, use DBNull.Value to send a NULL to the database rather than
546559
// using any default value assigned to the parameter.
547-
var p = new SqlParameter($"@{spName?.ParameterNamePrefix ?? contextParamPrefix?.Prefix}{columnName?.Name ?? mp.Name}",
560+
var p = new SqlParameter($"@{spName?.ParameterNamePrefix ?? contextParamPrefix?.Prefix}{columnName ?? mp.Name}",
548561
value ?? DBNull.Value);
549562
p.SetParameterType(paramType);
550563

0 commit comments

Comments
 (0)