Skip to content
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
12 changes: 8 additions & 4 deletions XCode/Code/EntityBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1176,7 +1176,7 @@ protected virtual void BuildMap()
mapName ??= mapTable.Columns.FirstOrDefault(e => e.Master);
mapName ??= mapTable.GetColumn("Name");
}
else
else if (ss.Length > 2)
{
// 默认字符串类型
mapName = new XField { Name = ss[2], DataType = typeof(String) };
Expand Down Expand Up @@ -1205,8 +1205,12 @@ protected virtual void BuildMap()
if (mapName != null && mapName.Name != "$") myName += mapName.Name;
}

// 扩展属性有可能恰巧跟已有字段同名
if (!myName.IsNullOrEmpty() && !Table.Columns.Any(e => e.Name.EqualIgnoreCase(myName)))
// $表示用ToString()替代显示字段
var useToString = ss.Length > 2 && ss[2] == "$";

// 扩展属性有可能恰巧跟已有字段同名,且需要有显示字段才能生成扩展属性
if (!myName.IsNullOrEmpty() && !Table.Columns.Any(e => e.Name.EqualIgnoreCase(myName))
&& (mapName != null || useToString))
{
var type = Option.Nullable ? "String?" : "String";

Expand All @@ -1215,7 +1219,7 @@ protected virtual void BuildMap()
WriteLine("[Map(nameof({0}), typeof({1}), \"{2}\")]", column.Name, fullName, mapIdName);
if (column.Properties.TryGetValue("Category", out var att) && !att.IsNullOrEmpty())
WriteLine("[Category(\"{0}\")]", att);
if (ss.Length > 2 && ss[2] == "$")
if (useToString)
WriteLine("public {2} {0} => {1}?.ToString();", myName, name, type);
else if (mapName != null)
{
Expand Down
66 changes: 66 additions & 0 deletions XUnitTest.XCode/Code/EntityBuilderTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using NewLife.Log;
Expand Down Expand Up @@ -400,6 +401,71 @@ public void FixModelFile()
Assert.Contains("Name", xml);
}

/// <summary>
/// 验证:Map特性只有表@主键(无显示字段),且被映射表无Master/Name字段时,
/// 不应生成孤立的[Map(...)]特性(缺少属性声明)
/// </summary>
[Fact]
public void BuildMap_NoDisplayField_NoOrphanedMapAttribute()
{
// 构造 ProductRelease 表(无 Master 字段,无 Name 字段)
var releaseTable = new XTable("ProductRelease") { Description = "产品版本" };
var releaseId = (XField)releaseTable.CreateColumn();
releaseId.Name = "Id";
releaseId.DataType = typeof(Int32);
releaseId.Identity = true;
releaseId.PrimaryKey = true;
releaseTable.Columns.Add(releaseId);

var releaseVersion = (XField)releaseTable.CreateColumn();
releaseVersion.Name = "Version";
releaseVersion.DataType = typeof(String);
releaseTable.Columns.Add(releaseVersion);

// 构造 ProductPackage 表,ReleaseId 的 Map 只有 "ProductRelease@Id"(无显示字段)
var packageTable = new XTable("ProductPackage") { Description = "产品发布包" };
var pkgId = (XField)packageTable.CreateColumn();
pkgId.Name = "Id";
pkgId.DataType = typeof(Int32);
pkgId.Identity = true;
pkgId.PrimaryKey = true;
packageTable.Columns.Add(pkgId);

var releaseIdCol = (XField)packageTable.CreateColumn();
releaseIdCol.Name = "ReleaseId";
releaseIdCol.DataType = typeof(Int32);
releaseIdCol.Map = "ProductRelease@Id";
releaseIdCol.Description = "发布版本。所属发布版本";
packageTable.Columns.Add(releaseIdCol);

var allTables = new List<IDataTable> { releaseTable, packageTable };

var option = new EntityBuilderOption
{
ConnName = "Test",
Namespace = "Test",
Nullable = true,
};

var builder = new EntityBuilder
{
Table = packageTable,
AllTables = allTables,
Option = option,
};

builder.Execute();
var code = builder.ToString();

Assert.NotEmpty(code);

// 验证不存在孤立的[Map(...)]特性(即[Map后面紧跟空行或#endregion)
Assert.DoesNotContain("[Map(nameof(ReleaseId)", code);

// 验证仍然生成了对象引用属性(ProductRelease对象),且使用 Extends.Get 模式
Assert.Contains("public ProductRelease? Release => Extends.Get(nameof(Release), k => ProductRelease.FindById(ReleaseId));", code);
}

[Fact(Skip = "跳过")]
public void Merge()
{
Expand Down