假设我的实体是
public class AppUser
{
string Id { get; set; }
string Name { get; set; }
}
默认情况下,Dapper Dommel不会插入Id字段。它会生成非常接近于此的SQL:
insert into AppUser (Name) values ("Dapper") select cast(scope_identity() as int)
这个SQL是使用Dapper Dommel Insert函数生成的,如下所示:
using (var connection = new System.Data.SqlClient.SqlConnection(ConnectionString))
{
connection.Open();
connection.Insert<AppUser>(new User { Id = "someGuid", Name = "Dapper" });
}
我希望它插入我为其提供值的Id列,也不执行select cast(scope_identity()as int)查询。也就是说,我想要这样的东西
insert into AppUser (Id, Name) values ("someGuid", "Dapper")
我似乎无法在文档中找到它。有谁知道如何实现这个目标?
答案 0 :(得分:0)
我不熟悉Dommel,但你可以使用.Execute:
_dbConnection.Execute(@"insert into AppUser (Id, Name)
values (@Id, @Name)", new {Id = 1, Name = "Foo"});
答案 1 :(得分:0)
在初步测试中,这对我有用。有效地,此代码告诉Dommel您的属性均未生成/计算。如果您具有要忽略的计算属性,则可能需要针对您的用例更加具体。到目前为止我还不需要。
internal class KeysNotGeneratedPropertyResolver : DommelPropertyResolver
{
public override IEnumerable<ColumnPropertyInfo> ResolveProperties(Type type)
{
return base.ResolveProperties(type)
.Select(column => new ColumnPropertyInfo(column.Property, DatabaseGeneratedOption.None));
}
}
internal class NotGeneratedKeyResolver : IKeyPropertyResolver
{
private static readonly IKeyPropertyResolver DefaultResolver = new DommelKeyPropertyResolver();
public ColumnPropertyInfo[] ResolveKeyProperties(Type type)
{
return DefaultResolver.ResolveKeyProperties(type)
.Select(info => new ColumnPropertyInfo(info.Property, DatabaseGeneratedOption.None))
.ToArray();
}
}
然后在您的配置中
DommelMapper.SetPropertyResolver(new KeysNotGeneratedPropertyResolver());
DommelMapper.SetKeyPropertyResolver(new NotGeneratedKeyResolver());
答案 2 :(得分:0)
由于库中的错误,“Id”属性被视为身份并从生成的插入语句中排除。将 Dapper-Dommel-FluentMap
库与下面提供的文件一起使用,您应该没问题。
我在使用 Dapper-Dommel-FluentMap
库(一个提供更多映射功能的互补姐妹库)时遇到了同样的问题,我在对其源代码进行了一些挖掘(几个小时)后设法找到了解决方案。
未插入 Id
属性的原因是因为 Dommel
和 Dommel-FluentMap
都将所有关键属性(或名为 Id
的属性)视为身份。
但是,在现实生活中的应用程序中,并非所有关键属性都是身份,因此这种行为是一个错误。
这有点fixed,并于 2021 年 6 月合并到官方 GitHub 存储库,但作者自 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);
}
}
添加以下 AppUser
Dommel 贴图:
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();