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
2 changes: 1 addition & 1 deletion src/LuYao.Common/Data/Attributes/RecordAttribute.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System;

namespace LuYao.Data;
namespace LuYao.Data.Attributes;

/// <summary>
/// 用于标记 Record 映射行为的特性基类。
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System;

namespace LuYao.Data;
namespace LuYao.Data.Attributes;

/// <summary>
/// 标记属性对应的列名称,优先级高于 <see cref="RecordNamingPolicy"/>。
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using LuYao.Data.Mapping;
using System;

namespace LuYao.Data;
namespace LuYao.Data.Attributes;

/// <summary>
/// 声明属性在 <see cref="RecordTable"/> 中的列存储类型,优先级高于 <see cref="RecordMappingOptions"/> 的全局策略。
Expand Down
2 changes: 1 addition & 1 deletion src/LuYao.Common/Data/Binary/BinaryPayloadHeader.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System;
using System.IO;

namespace LuYao.Data;
namespace LuYao.Data.Binary;

internal enum BinaryPayloadType : byte
{
Expand Down
2 changes: 1 addition & 1 deletion src/LuYao.Common/Data/Binary/RecordBinaryPayloadCodec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using System.IO;
using System.IO.Compression;

namespace LuYao.Data;
namespace LuYao.Data.Binary;

/// <summary>
/// Record 二进制负载编解码器。
Expand Down
2 changes: 1 addition & 1 deletion src/LuYao.Common/Data/Binary/RecordPayloadCompression.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace LuYao.Data;
namespace LuYao.Data.Binary;

/// <summary>
/// 指定 <see cref="RecordBinaryPayloadCodec"/> 序列化时使用的压缩算法。
Expand Down
3 changes: 2 additions & 1 deletion src/LuYao.Common/Data/Json/RecordSetJsonConverter.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#if !NET45 && !NET461
using LuYao.Data.Binary;
using System;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace LuYao.Data;
namespace LuYao.Data.Json;

/// <summary>
/// 将 <see cref="RecordSet"/> 以 Base64 二进制格式进行 JSON 序列化/反序列化。
Expand Down
3 changes: 2 additions & 1 deletion src/LuYao.Common/Data/Json/RecordTableJsonConverter.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
#if !NET45 && !NET461
using LuYao.Data.Binary;
using System;
using System.IO;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace LuYao.Data;
namespace LuYao.Data.Json;

/// <summary>
/// 将 <see cref="RecordTable"/> 以 Base64 二进制格式进行 JSON 序列化/反序列化。
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using LuYao.Data.Attributes;
using LuYao.Data.Meta;
using System.Reflection;

namespace LuYao.Data.Meta;
namespace LuYao.Data.Mapping;

/// <summary>
/// 根据 <see cref="RecordMappingOptions"/> 解析属性对应的列名。
Expand Down
14 changes: 0 additions & 14 deletions src/LuYao.Common/Data/Mapping/Converters/StringToInt32Converter.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using LuYao.Data.Meta;
using System;

namespace LuYao.Data.Meta;
namespace LuYao.Data.Mapping;

/// <summary>
/// Encapsulates the execution context for a single mapping operation.
Expand Down Expand Up @@ -51,14 +52,7 @@ internal void MapDtoToRow(Type type, object data, RecordRow target)
continue;
}

// Not natively supported: a converter (property type → column type) is required.
var converter = ResolveWriteConverter(prop, col.Type);
if (converter == null)
{
HandleUnsupportedTypeForWrite(prop);
continue;
}
col.Set(target, converter.Convert(prop.Type, col.Type, prop.GetValue(data)));
HandleUnsupportedTypeForWrite(prop);
}
}

Expand All @@ -84,22 +78,7 @@ internal void WriteDtoToRow(Type type, object data, RecordRow target)
continue;
}

// Not natively supported: determine the target column type.
var colType = ResolveColumnType(prop);
if (colType == null)
{
HandleUnsupportedTypeForWrite(prop);
continue;
}
var converter = ResolveWriteConverter(prop, colType);
if (converter == null)
{
ThrowMissingConverter(prop, colType);
continue;
}
var name = ColumnNameResolver.Resolve(prop, _options);
var destCol = cols.Find(name) ?? cols.Add(name, colType);
destCol.Set(target, converter.Convert(prop.Type, colType, prop.GetValue(data)));
HandleUnsupportedTypeForWrite(prop);
}
}

Expand Down Expand Up @@ -128,21 +107,9 @@ internal void MapRowToDto(Type type, object data, RecordRow source)
continue;
}

// Column type differs from property type, or property type is not natively
// supported: a converter (column type → property type) is required.
var converter = _options.FindConverter(col.Type, prop.Type)
?? (DefaultRecordConverter.Instance.CanConvert(col.Type, prop.Type)
? DefaultRecordConverter.Instance : null);

if (converter == null)
{
HandleConversionFailure(
new NotSupportedException(
$"Property '{prop.Name}' has type '{prop.Type.FullName}' which is not supported and no custom converter is registered."));
continue;
}

TryConvertAndSetValue(data, prop, col.Type, prop.Type, rawValue, converter);
HandleConversionFailure(
new NotSupportedException(
$"Property '{prop.Name}' has type '{prop.Type.FullName}' which is not supported."));
}
}

Expand Down Expand Up @@ -172,64 +139,10 @@ internal void AddColumnsFrom(Type type, RecordColumnCollection columns)
continue;
}

var colType = ResolveColumnType(prop);
if (colType == null)
{
HandleUnsupportedTypeForWrite(prop);
continue;
}
var converter = ResolveWriteConverter(prop, colType);
if (converter == null)
{
ThrowMissingConverter(prop, colType);
continue;
}
var name = ColumnNameResolver.Resolve(prop, _options);
columns.Add(name, colType);
HandleUnsupportedTypeForWrite(prop);
}
}

// ─── Private: column-type and converter resolution ───────────────────────────

/// <summary>
/// Determines the target column type for a property that is not natively supported.
/// Priority: <see cref="RecordColumnStorageAttribute"/> &gt; <see cref="UnsupportedTypeHandling"/>
/// (ConvertToString / ConvertToBytes). Returns <see langword="null"/> when Skip or Throw applies.
/// </summary>
private Type? ResolveColumnType(XProp prop)
{
var attr = prop.GetCustomAttribute<RecordColumnStorageAttribute>();
if (attr != null)
{
return attr.Target switch
{
RecordColumnStorageTarget.String => typeof(string),
RecordColumnStorageTarget.Bytes => typeof(byte[]),
_ => null, // Skip
};
}

return _options.UnsupportedTypeHandling switch
{
UnsupportedTypeHandling.ConvertToString => typeof(string),
UnsupportedTypeHandling.ConvertToBytes => typeof(byte[]),
_ => null,
};
}

/// <summary>
/// Resolves a write-direction converter (property type → column type).
/// Priority: options-registered converter &gt; <see cref="DefaultRecordConverter"/>.
/// </summary>
private RecordConverter? ResolveWriteConverter(XProp prop, Type colType)
{
var converter = _options.FindConverter(prop.Type, colType);
if (converter != null) return converter;
if (DefaultRecordConverter.Instance.CanConvert(prop.Type, colType))
return DefaultRecordConverter.Instance;
return null;
}

private void TrySetValue(object data, XProp prop, object? value)
{
try
Expand All @@ -242,23 +155,6 @@ private void TrySetValue(object data, XProp prop, object? value)
}
}

/// <summary>
/// Invokes the converter then assigns the result; any exception during conversion or
/// assignment is handled according to the <see cref="ConversionFailureHandling"/> policy.
/// </summary>
private void TryConvertAndSetValue(object data, XProp prop, Type sourceType, Type targetType, object? value, RecordConverter converter)
{
try
{
var converted = converter.Convert(sourceType, targetType, value);
prop.SetValue(data, converted);
}
catch (Exception ex) when (_options.ConversionFailureHandling == ConversionFailureHandling.Skip)
{
_ = ex;
}
}

private void HandleUnsupportedTypeForWrite(XProp prop)
{
if (_options.UnsupportedTypeHandling == UnsupportedTypeHandling.Throw)
Expand All @@ -274,10 +170,5 @@ private void HandleConversionFailure(Exception inner)
// Skip: silently ignore
}

private static void ThrowMissingConverter(XProp prop, Type colType)
{
throw new InvalidOperationException(
$"Property '{prop.Name}' (type '{prop.Type.FullName}') is declared to be stored as '{colType.Name}', " +
$"but no matching RecordConverter is registered in RecordMappingOptions and it is not covered by the default converter.");
}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using LuYao.Data.Attributes;
using System;
using System.Collections.Generic;

namespace LuYao.Data;
namespace LuYao.Data.Mapping;

/// <summary>
/// 控制 <see cref="RecordTable"/> 与 DTO 之间映射行为的选项类。
Expand Down Expand Up @@ -82,40 +82,4 @@ public ConversionFailureHandling ConversionFailureHandling
get => _conversionFailureHandling;
set { ThrowIfReadOnly(); _conversionFailureHandling = value; }
}

// ─── 自定义类型转换器 ──────────────────────────────────────────────────────────

private List<RecordConverter>? _converters;

/// <summary>
/// 注册自定义双向转换器。
/// 转换器同时用于 DTO → Table(写)和 Table → DTO(读)两个方向。
/// </summary>
/// <param name="converter">转换器实例,不可为 null。</param>
/// <exception cref="ArgumentNullException"><paramref name="converter"/> 为 null。</exception>
/// <exception cref="InvalidOperationException">实例已被冻结时抛出。</exception>
public void AddConverter(RecordConverter converter)
{
if (converter == null) throw new ArgumentNullException(nameof(converter));
ThrowIfReadOnly();
if (_converters == null) _converters = new List<RecordConverter>();
_converters.Add(converter);
}

/// <summary>
/// 查找支持从 <paramref name="sourceType"/> 到 <paramref name="targetType"/> 转换的已注册转换器。
/// 不包含托底转换器 <see cref="Meta.DefaultRecordConverter"/>。
/// </summary>
/// <param name="sourceType">来源类型。</param>
/// <param name="targetType">目标类型。</param>
/// <returns>匹配的转换器;未找到则返回 <see langword="null"/>。</returns>
internal RecordConverter? FindConverter(Type sourceType, Type targetType)
{
if (_converters == null) return null;
foreach (var c in _converters)
{
if (c.CanConvert(sourceType, targetType)) return c;
}
return null;
}
}
16 changes: 0 additions & 16 deletions src/LuYao.Common/Data/Mapping/XConverter.cs

This file was deleted.

Loading
Loading