TL;DR;
由于库中的错误,'Id' 属性被视为身份并从生成的插入语句中排除。将Dapper-Dommel-FluentMap 库与下面提供的文件一起使用,应该没问题。
解释:
Dapper-Dommel-FluentMap 库(一个提供更多映射功能的互补姐妹库)我也遇到了同样的问题,我在对其源代码进行了一些研究(几个小时)后设法找到了解决方案。
Id 属性未插入的原因是因为Dommel 和Dommel-FluentMap 都将所有关键属性(或名为Id 的属性)视为身份。
然而,在现实生活中的应用程序中,并非所有关键属性都是身份,这使得这种行为成为一个错误。
这有点fixed,并于2021年6月合并到官方GitHub repo,但作者自8/23/2020以来一直没有更新NuGet包,质疑这个库的可靠性。所以,如果我们想继续使用Dapper-Dommel,我们只有一个选择:用我们自己的实现覆盖默认属性和关键属性解析器。
或者,您可以在Dapper-Dommel 库中推出自己的自定义实现,但您自己在那里。
解决方案
首先添加Dapper.FluentMap.Dommel NuGet 包。
之后,在您的项目中添加以下文件:
public class CustomDommelPropertyResolver : DefaultPropertyResolver
{
private static readonly IPropertyResolver DefaultResolver = new DefaultPropertyResolver();
/// <inheritdoc/>
protected override IEnumerable<PropertyInfo> FilterComplexTypes(IEnumerable<PropertyInfo> properties)
{
foreach (var propertyInfo in properties)
{
var type = propertyInfo.PropertyType;
type = Nullable.GetUnderlyingType(type) ?? type;
if (type.GetTypeInfo().IsPrimitive || type.GetTypeInfo().IsEnum || PrimitiveTypes.Contains(type))
{
yield return propertyInfo;
}
}
}
/// <inheritdoc/>
public override IEnumerable<ColumnPropertyInfo> ResolveProperties(Type type)
{
IEntityMap entityMap;
if (FluentMapper.EntityMaps.TryGetValue(type, out entityMap))
{
foreach (var property in FilterComplexTypes(type.GetProperties()))
{
// Determine whether the property should be ignored.
var propertyMap = entityMap.PropertyMaps.FirstOrDefault(p => p.PropertyInfo.Name == property.Name);
if (propertyMap == null || !propertyMap.Ignored)
{
var dommelPropertyMap = propertyMap as DommelPropertyMap;
if (dommelPropertyMap != null)
{
yield return new ColumnPropertyInfo(property, dommelPropertyMap.GeneratedOption != default
? dommelPropertyMap.GeneratedOption
: (dommelPropertyMap.Identity ? DatabaseGeneratedOption.Identity : DatabaseGeneratedOption.None));
}
else
{
yield return new ColumnPropertyInfo(property);
}
}
}
}
else
{
foreach (var property in DefaultResolver.ResolveProperties(type))
{
yield return property;
}
}
}
}
和
public class CustomDommelKeyPropertyResolver : IKeyPropertyResolver
{
private static readonly IKeyPropertyResolver DefaultResolver = new DefaultKeyPropertyResolver();
/// <inheritdoc/>
public ColumnPropertyInfo[] ResolveKeyProperties(Type type)
{
IEntityMap entityMap;
if (!FluentMapper.EntityMaps.TryGetValue(type, out entityMap))
{
return DefaultResolver.ResolveKeyProperties(type);
}
var mapping = entityMap as IDommelEntityMap;
if (mapping != null)
{
var allPropertyMaps = entityMap.PropertyMaps.OfType<DommelPropertyMap>();
var keyPropertyInfos = allPropertyMaps
.Where(e => e.Key)
.Select(x => new ColumnPropertyInfo(x.PropertyInfo, x.GeneratedOption != default
? x.GeneratedOption
: (x.Identity ? DatabaseGeneratedOption.Identity : DatabaseGeneratedOption.None)))
.ToArray();
// Now make sure there aren't any missing key properties that weren't explicitly defined in the mapping.
try
{
// Make sure to exclude any keys that were defined in the dommel entity map and not marked as keys.
var defaultKeyPropertyInfos = DefaultResolver.ResolveKeyProperties(type).Where(x => allPropertyMaps.Count(y => y.PropertyInfo.Equals(x.Property)) == 0);
keyPropertyInfos = keyPropertyInfos.Union(defaultKeyPropertyInfos).ToArray();
}
catch
{
// There could be no default Ids found. This is okay as long as we found a custom one.
if (keyPropertyInfos.Length == 0)
{
throw new InvalidOperationException($"Could not find the key properties for type '{type.FullName}'.");
}
}
return keyPropertyInfos;
}
// Fall back to the default mapping strategy.
return DefaultResolver.ResolveKeyProperties(type);
}
}
添加以下AppUserDommel地图:
public class AppUserMap : DommelEntityMap<AppUser>
{
public AppUserMap()
{
Map(p => p.Id).ToColumn("Id")
.IsKey()
.SetGeneratedOption(DatabaseGeneratedOption.None)
.Identity = false; // explicitly specified for clarity
Map(x => x.Name).ToColumn("Name");
}
}
在Dommel's FluentMapper初始化方法中添加地图:
FluentMapper.Initialize(config =>
{
config.AddMap(new AppUserMap());
config.ForDommel();
});
确保之后覆盖 Dommel 的默认解析器:
DommelMapper.SetKeyPropertyResolver(new CustomDommelKeyPropertyResolver());
DommelMapper.SetPropertyResolver(new CustomDommelPropertyResolver());
有了这个,除非您明确指定属性的数据库生成选项或身份,否则它们不会被选为身份。
修复此错误的代码如下:
.Select(x => new ColumnPropertyInfo(x.PropertyInfo, x.GeneratedOption != default
? x.GeneratedOption
: (x.Identity ? DatabaseGeneratedOption.Identity : DatabaseGeneratedOption.None)))
.ToArray();